<!DOCTYPE html>
<html>
<head><meta name="generator" content="Hexo 3.9.0">
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    
    <title>
        Archives: 2018 |
        
        Darklovy</title>
    <meta name="description" content>
    <meta name="keywords" content>
    <meta name="HandheldFriendly" content="True">
    <meta name="apple-mobile-web-app-capable" content="yes">
    <link rel="shortcut icon" href="/">
    <link rel="alternate" href="/atom.xml" title="Darklovy">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <meta property="og:type" content="website">
<meta property="og:title" content="Darklovy">
<meta property="og:url" content="https://www.ttxxly.top/archives/2018/index.html">
<meta property="og:site_name" content="Darklovy">
<meta property="og:locale" content="en">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Darklovy">

    <link href="https://fonts.googleapis.com/css?family=Inconsolata|Titillium+Web" rel="stylesheet">
    <link href="https://fonts.googleapis.com/css?family=Roboto+Mono" rel="stylesheet">
    <link href="//cdn.bootcss.com/node-waves/0.7.5/waves.min.css" rel="stylesheet">
    <link rel="stylesheet" href="/style.css">
    <script>
        function setLoadingBarProgress(num) {
            document.getElementById('loading-bar').style.width = num + "%";
        }
    </script>
</head>
</html>
<body>
  <div id="loading-bar-wrapper">
  <div id="loading-bar"></div>
</div>


  <script>setLoadingBarProgress(20)</script> 
  <header class="l_header">
	<div class='wrapper'>
		<div class="nav-main container container--flex">
			<a class="logo flat-box" href='/' >
				Darklovy
			</a>
			<div class='menu'>
				<ul class='h-list'>
					
						<li>
							<a class='flat-box nav-Home' href='/'>
								首页
							</a>
						</li>
					
						<li>
							<a class='flat-box nav-archives' href='/archives'>
								归档
							</a>
						</li>
					
						<li>
							<a class='flat-box nav-categories' href='/categories'>
								分类
							</a>
						</li>
					
						<li>
							<a class='flat-box nav-tags' href='/tags'>
								标签
							</a>
						</li>
					
						<li>
							<a class='flat-box nav-algorithm' href='https://book.algorithm.ttxxly.top/'>
								算法
							</a>
						</li>
					
						<li>
							<a class='flat-box nav-python' href='https://book.python.ttxxly.top/'>
								python
							</a>
						</li>
					
						<li>
							<a class='flat-box nav-about' href='/about'>
								关于
							</a>
						</li>
					
				</ul>
				<div class='underline'></div>
			</div>
			
				<div class="m_search">
					<form name="searchform" class="form u-search-form">
						<input type="text" class="input u-search-input" placeholder="Search" />
						<span class="icon icon-search"></span>
					</form>
				</div>
			
			<ul class='switcher h-list'>
				
					<li class='s-search'><a href='javascript:void(0)'><span class="icon icon-search flat-box"></span></a></li>
				
				<li class='s-menu'><a href='javascript:void(0)'><span class="icon icon-menu flat-box"></span></a></li>
			</ul>
		</div>
		
		<div class='nav-sub container container--flex'>
			<a class="logo" class="flat-box" href='javascript:void(0)'>
				Word of Forks
			</a>

			<ul class='switcher h-list'>
				<li class='s-comment'><a href='javascript:void(0)'><span class="icon icon-chat_bubble_outline flat-box"></span></a></li>
				<li class='s-top'><a href='javascript:void(0)'><span class="icon icon-arrow_upward flat-box"></span></a></li>
				<li class='s-toc'><a href='javascript:void(0)'><span class="icon icon-format_list_numbered flat-box"></span></a></li>
			</ul>
		</div>
	</div>
</header>
<aside class="menu-phone">
	<nav>
		
			<a href="/" class="nav-Home nav">
				首页
			</a>
		
			<a href="/archives" class="nav-archives nav">
				归档
			</a>
		
			<a href="/categories" class="nav-categories nav">
				分类
			</a>
		
			<a href="/tags" class="nav-tags nav">
				标签
			</a>
		
			<a href="https://book.algorithm.ttxxly.top/" class="nav-algorithm nav">
				算法
			</a>
		
			<a href="https://book.python.ttxxly.top/" class="nav-python nav">
				python
			</a>
		
			<a href="/about" class="nav-about nav">
				关于
			</a>
		
	</nav>
</aside>

    <script>setLoadingBarProgress(40);</script>
  <div class="l_body">
    <div class='container clearfix'>
      <div class='l_main'>
        
	
  <script>
    window.subData= { title:'Year : 2018'}
  </script>

<section class="post-list">
	
    <div class='post-wrapper'>
      <article class="post reveal">
  <section class="meta">
    
    <h2 class="title">
      <a href="/2018/10/28/Android-简介/">
        Android 简介
      </a>
    </h2>
    
    <time>
      Oct 28, 2018
    </time>
		
    
    <div class='cats'>
        <a href="/categories/Android基础/">Android基础</a>
    </div>

  </section>
  <section class="article typo">
	  <p>Android 从面世以来到现在已经发布了二十几个版本了。在这几年的发展过程中，谷歌为Android 王国建立了一个完整的生态系统。手机厂商、开发者、用户之间相互依存，共同推进着Android的蓬勃发展。</p>
<h3 id="Android-系统架构"><a href="#Android-系统架构" class="headerlink" title="Android 系统架构"></a>Android 系统架构</h3><p>为了更好的理解 Android 系统是怎么工作的，我们先来看一下它的系统架构。Android 大致可以分为四层架构：Linux 内核层、系统运行库层、应用框架层和应用层。</p>
<h4 id="Linux-内核层"><a href="#Linux-内核层" class="headerlink" title="Linux 内核层"></a>Linux 内核层</h4><p>Android 系统是基于 Linux内核的，这一层为 Android 设备的各种硬件提供了底层的驱动，如显示驱动、音频驱动、照相机驱动、蓝牙驱动、Wi-Fi驱动、电源管理等。</p>
<h4 id="系统运行库层"><a href="#系统运行库层" class="headerlink" title="系统运行库层"></a>系统运行库层</h4><p>这一层通过一些 C/C++ 库来为 Android 系统提供了主要的特性支持。如SQLite 库提供了数据库的支持，OpenGL/ES 库提供了 3D 绘图的支持，WebKit 库提供了浏览器内核的支持等。</p>
<p>同样在这一层还有 Android 运行时库，它主要提供了一些核心库，能够允许开发者使用 Java 语言来编写 Android 应用。另外，Android 运行时库中还包含了 Dalvik 虚拟机（5.0 系统之后改为 ART 运行环境），它使得每一个 Android 应用都能运行在独立的进程当中，并且拥有一个自己的 Dalvik 虚拟机实例。相较于 Java 虚拟机，Dalvik 时专门为移动设备定制的，它针对手机内存、CPU性能有限等情况做了优化处理。</p>
<h4 id="应用框架层"><a href="#应用框架层" class="headerlink" title="应用框架层"></a>应用框架层</h4><p>这一层主要提供了构建应用程序时可能用到的各种 API， Android 自带的一些核心应用就是使用这些 APi 完成的，开发者也可以通过使用这些 API 来构建自己的应用城固县。</p>
<h4 id="应用层"><a href="#应用层" class="headerlink" title="应用层"></a>应用层</h4><p>所有安装在手机上的应用程序都是属于这一层的，比如系统自带的联系人、短信等程序，或者是你从 GooGle Play 上下载的小游戏，当然还包括你自己开发的程序等。</p>
<h3 id="Android-已发布的版本"><a href="#Android-已发布的版本" class="headerlink" title="Android 已发布的版本"></a>Android 已发布的版本</h3><p>2008 年 9 月，谷歌正式发布了 Android 1.0 系统，这也是 Android 系统最早的版本。随后的几年，谷歌以惊人的速度不断地更新 Android 系统。<br>具体如下图所示：</p>
<p>数据来源：<a href="https://developer.android.com/about/dashboards/" target="_blank" rel="noopener">戳我</a></p>
<p><img src="/images/2018-10-28/2.png" alt></p>
<h3 id="Android-应用开发特色"><a href="#Android-应用开发特色" class="headerlink" title="Android 应用开发特色"></a>Android 应用开发特色</h3><ul>
<li>四大组件：活动（Activity）、服务（Service）、广播接收器（Broadcast Receiver）和内容提供器（Content Provider）。</li>
<li>丰富的系统控件</li>
<li>SQLite 数据库</li>
<li>强大的多媒体</li>
<li>地理位置定位</li>
</ul>


    
    
    
	  <div class="full-width auto-padding tags">
      
        <a href="/tags/Android/">Android</a>
      
	  </div>
    
  </section>
</article>
    </div>
  
    <div class='post-wrapper'>
      <article class="post reveal">
  <section class="meta">
    
    <h2 class="title">
      <a href="/2018/10/28/HTML-简介/">
        HTML 简介
      </a>
    </h2>
    
    <time>
      Oct 28, 2018
    </time>
		
  </section>
  <section class="article typo">
	  <p>超文本标记语言（HyperText Markup Language，简称：HTML）是一种用于创建网页的标准标记语言。<br>您可以使用 HTML 来建立自己的 WEB 站点， HTML 运行在浏览器上，由浏览器来解析。</p>
<h3 id="什么是-HTML-？"><a href="#什么是-HTML-？" class="headerlink" title="什么是 HTML ？"></a>什么是 HTML ？</h3><p>HTML 是用来描述网页的一种语言。</p>
<ul>
<li>HTML 指的是超文本标记语言：HyperText Markup Language</li>
<li>HTML 不是一种编程语言，而是一种标记语言。</li>
<li>标记语言是一套标记标签（Markup tag）</li>
<li>HTML 使用标记标签来描网页。</li>
<li>HTML 文档包含了 HTML 标签以及文本内容</li>
<li>HTMl 文档也叫做 WEB 页面</li>
</ul>
<h3 id="HTML-标签"><a href="#HTML-标签" class="headerlink" title="HTML 标签"></a>HTML 标签</h3><p>HTML 标记标签通常被称为 HTML 标签（HTML tag）</p>
<ul>
<li>HTML 标签是由尖括号包围的关键词，比如 <code>&lt;html&gt;</code></li>
<li>HTML 标签通常是成队出现的，比如 <code>&lt;b&gt;</code> 和 <code>&lt;/b&gt;</code></li>
<li>标签对中的第一个标签是开始标签，第二个标签是结束标签。</li>
<li>开始和结束标签也被称为开放标签和闭合标签</li>
</ul>
<h3 id="lt-DOCTYPE-gt-声明"><a href="#lt-DOCTYPE-gt-声明" class="headerlink" title="&lt;!DOCTYPE&gt; 声明"></a><code>&lt;!DOCTYPE&gt;</code> 声明</h3><p>&lt;!DOCTYPE&gt;声明有助于浏览器中正确显示网页。</p>
<p>网络上有很多不同的文件，如果能够正确声明HTML的版本，浏览器就能正确显示网页内容。</p>
<p>doctype 声明是不区分大小写的，以下方式均可：</p>
<figure class="highlight html"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">&lt;!DOCTYPE html&gt;</span> </span><br><span class="line"><span class="meta">&lt;!DOCTYPE HTML&gt;</span> </span><br><span class="line"><span class="meta">&lt;!doctype html&gt;</span> </span><br><span class="line"><span class="meta">&lt;!Doctype Html&gt;</span></span><br></pre></td></tr></table></figure>


    
    
    
	  <div class="full-width auto-padding tags">
      
        <a href="/tags/HTML/">HTML</a>
      
	  </div>
    
  </section>
</article>
    </div>
  
    <div class='post-wrapper'>
      <article class="post reveal">
  <section class="meta">
    
    <h2 class="title">
      <a href="/2018/10/28/Java-变量与常量/">
        Java 变量与常量
      </a>
    </h2>
    
    <time>
      Oct 28, 2018
    </time>
		
  </section>
  <section class="article typo">
	  <p>在程序执行过程中，其值不能被改变的量称为常量，其值能被改变的量被称为变量。变量与常量的命名都必须使用合法的标识符。</p>
<h3 id="标识符和关键字"><a href="#标识符和关键字" class="headerlink" title="标识符和关键字"></a>标识符和关键字</h3><h4 id="标识符"><a href="#标识符" class="headerlink" title="标识符"></a>标识符</h4><p>标识符可以简单地理解为一个名字，用来标识类名、方法名、数组名、文件名的有效字符序列。</p>
<p><strong>Java 语言规定标识符由任意顺序的字母、下划线、美元符号和数字组成，并且第一个字符不能是数字。</strong><br><strong>标识符不能是 Java 中的保留字，并且在 Java 语言中的字母是严格区分大小写的。</strong></p>
<h4 id="关键字"><a href="#关键字" class="headerlink" title="关键字"></a>关键字</h4><p>关键字是 Java 语言中已经被赋予特定意义的一些单词，不可以把这些字作为标识符来使用。</p>
<p><img src="/images/2018-10-28/1.png" alt></p>
<h3 id="声明变量"><a href="#声明变量" class="headerlink" title="声明变量"></a>声明变量</h3><p>变量饿使用是程序谁中一个十分重要的环；。定义变量就是要告诉编译器（compiler）这个变量的数据类型，这样编译器才知道许哟啊配置多少空间给它，以及它能够存储怎样的数据。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">int</span> age;</span><br><span class="line"><span class="keyword">char</span> char1 = <span class="string">'Y'</span>;</span><br></pre></td></tr></table></figure>
<p><strong>对变量的命名，应该遵循下面的规则</strong></p>
<ul>
<li>变量名必须是一个有效的标识符</li>
<li>变量名不能重复</li>
<li>变量名应该是有意义的</li>
</ul>
<p><em>注：在 Java 语言中是允许使用汉字或其他语言文字作为变量名，但不建议这样做。</em></p>
<h3 id="声明常量"><a href="#声明常量" class="headerlink" title="声明常量"></a>声明常量</h3><p>在程序运行过程中一直不会改变的量称为常量（constant），通常也称为 “final 变量”。常量在整个程序中通常只能被赋值一次。在为所有的对象共享值时，常量时非常有用的。</p>
<h4 id="声明常量的标准语言以及例子"><a href="#声明常量的标准语言以及例子" class="headerlink" title="声明常量的标准语言以及例子"></a>声明常量的标准语言以及例子</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">final</span> 数据类型 常量名称[=值];</span><br><span class="line"></span><br><span class="line"><span class="keyword">final</span> <span class="keyword">double</span> p1 = <span class="number">3.1415926</span>;</span><br><span class="line"><span class="keyword">final</span> <span class="keyword">boolean</span> b1 = <span class="keyword">true</span>;</span><br></pre></td></tr></table></figure>
<h3 id="变量的有效范围"><a href="#变量的有效范围" class="headerlink" title="变量的有效范围"></a>变量的有效范围</h3><p>由于变量被定义出来后只是暂存在内存中，等到程序执行到某一个点，该变量会被释放掉，也就是说变量有它的生命周期。</p>
<p>按照变量的有效范围将变量分为成员变量和局部变量。</p>
<h4 id="成员变量"><a href="#成员变量" class="headerlink" title="成员变量"></a>成员变量</h4><p>在类体中定义的变量被称为成员变量，成员变量在整个类中都有效。类的成员变量又可以分为静态变量和实例变量。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="class"><span class="keyword">class</span> <span class="title">var</span> </span>&#123;</span><br><span class="line">    <span class="keyword">int</span> x = <span class="number">45</span>;</span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">int</span> y = <span class="number">90</span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>在成员变量的类型前面加上关键字 static 后，这样的变量就被称为静态变量。对于静态变量，除了能在定义它的类存取，还可以以“类名.静态变量”的方式在其他类中使用。</p>
<h4 id="局部变量"><a href="#局部变量" class="headerlink" title="局部变量"></a>局部变量</h4><p>在类的方体中定义的变量称为局部变量。布局变量只在当前代码块中有效。</p>
<p>在类的方法中声明的变量，包括方法的参数，都属于局部变量。局部变量的生命周期取决于方法，当单发被调用时，Java 虚拟机为方法中的局部变量分配内存空间，当该方法的调用结束后，则会释放方法中局部变量占用的内存空间，局部变量也将会销毁。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">val</span></span>&#123;</span><br><span class="line">    <span class="keyword">static</span> <span class="keyword">int</span> times = <span class="number">3</span>;<span class="comment">//定义成员变量</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span></span>&#123;</span><br><span class="line">        <span class="keyword">int</span> times = <span class="number">4</span>;<span class="comment">//定义局部变量</span></span><br><span class="line">        System.out.println(<span class="string">"Times 的值为："</span>+times);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

    
    
    
	  <div class="full-width auto-padding tags">
      
        <a href="/tags/Java/">Java</a>
      
	  </div>
    
  </section>
</article>
    </div>
  
    <div class='post-wrapper'>
      <article class="post reveal">
  <section class="meta">
    
    <h2 class="title">
      <a href="/2018/10/28/Python-简介/">
        Python 简介
      </a>
    </h2>
    
    <time>
      Oct 28, 2018
    </time>
		
  </section>
  <section class="article typo">
	  <p>Python 是一个高层次的结合了解释性、编译性、互动性和面向对象的脚本语言。</p>
<p>Python 的设计具有很强的可读性，相比其他语言经常使用英文关键字，其他语言的一些标点符号，它具有比其他语言更有特色语法结构。</p>
<ul>
<li><strong>Python 是一种解释型语言：</strong> 这意味着开发过程中没有了编译这个环节。类似于PHP和Perl语言。</li>
<li><strong>Python 是交互式语言：</strong> 这意味着，您可以在一个Python提示符，直接互动执行写你的程序。</li>
<li><strong>Python 是面向对象语言:</strong> 这意味着Python支持面向对象的风格或代码封装在对象的编程技术。</li>
<li><strong>Python 是初学者的语言：</strong>Python 对初级程序员而言，是一种伟大的语言，它支持广泛的应用程序开发，从简单的文字处理到 WWW 浏览器再到游戏。</li>
</ul>
<hr>
<h3 id="Python-发展历史"><a href="#Python-发展历史" class="headerlink" title="Python 发展历史"></a>Python 发展历史</h3><p>Python 是由 Guido van Rossum 在八十年代末和九十年代初，在荷兰国家数学和计算机科学研究所设计出来的。</p>
<p>Python 本身也是由诸多其他语言发展而来的,这包括 ABC、Modula-3、C、C++、Algol-68、SmallTalk、Unix shell 和其他的脚本语言等等。</p>
<p>像 Perl 语言一样，Python 源代码同样遵循 GPL(GNU General Public License)协议。</p>
<p>现在 Python 是由一个核心开发团队在维护，Guido van Rossum 仍然占据着至关重要的作用，指导其进展。</p>
<hr>
<h3 id="Python-特点"><a href="#Python-特点" class="headerlink" title="Python 特点"></a>Python 特点</h3><ul>
<li><strong>1.易于学习：</strong>Python有相对较少的关键字，结构简单，和一个明确定义的语法，学习起来更加简单。</li>
<li><strong>2.易于阅读：</strong>Python代码定义的更清晰。</li>
<li><strong>3.易于维护：</strong>Python的成功在于它的源代码是相当容易维护的。</li>
<li><strong>4.一个广泛的标准库：</strong>Python的最大的优势之一是丰富的库，跨平台的，在UNIX，Windows和Macintosh兼容很好。</li>
<li><strong>5.互动模式：</strong>互动模式的支持，您可以从终端输入执行代码并获得结果的语言，互动的测试和调试代码片断。</li>
<li><strong>6.可移植：</strong>基于其开放源代码的特性，Python已经被移植（也就是使其工作）到许多平台。</li>
<li><strong>7.可扩展：</strong>如果你需要一段运行很快的关键代码，或者是想要编写一些不愿开放的算法，你可以使用C或C++完成那部分程序，然后从你的Python程序中调用。</li>
<li><strong>8.数据库：</strong>Python提供所有主要的商业数据库的接口。</li>
<li><strong>9.GUI编程：</strong>Python支持GUI可以创建和移植到许多系统调用。</li>
<li><strong>10.可嵌入:</strong> 你可以将Python嵌入到C/C++程序，让你的程序的用户获得”脚本化”的能力。</li>
</ul>


    
    
    
	  <div class="full-width auto-padding tags">
      
        <a href="/tags/Python/">Python</a>
      
	  </div>
    
  </section>
</article>
    </div>
  
    <div class='post-wrapper'>
      <article class="post reveal">
  <section class="meta">
    
    <h2 class="title">
      <a href="/2018/10/26/Java-基本数据类型/">
        Java 基本数据类型
      </a>
    </h2>
    
    <time>
      Oct 26, 2018
    </time>
		
  </section>
  <section class="article typo">
	  <p>在 Java 中有 8 种基本数据类型来存储数值、字符和布尔值。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">数值型：</span><br><span class="line">    整数类型：<span class="keyword">byte</span>、<span class="keyword">short</span>、<span class="keyword">int</span>、<span class="keyword">long</span></span><br><span class="line">    浮点类型：<span class="keyword">float</span>、<span class="keyword">double</span></span><br><span class="line">字符型：<span class="keyword">char</span></span><br><span class="line">布尔型：<span class="keyword">boolean</span></span><br></pre></td></tr></table></figure>
<h3 id="整数类型"><a href="#整数类型" class="headerlink" title="整数类型"></a>整数类型</h3><p>整数类型用来存储整数数值，即没有小数部分的数值。可以是正数，也可以是负数。整数数据在<br>Java 程序中有 3 种表示方式，分别为 十进制、八进制和十六进制。</p>
<h4 id="十进制"><a href="#十进制" class="headerlink" title="十进制"></a>十进制</h4><p>十进制的表现形式是最常见的，如 120、0、-127.</p>
<p><em>注意：不能以 0 作为十进制数的开头（0 除外）</em></p>
<h4 id="八进制"><a href="#八进制" class="headerlink" title="八进制"></a>八进制</h4><p>如 0123（转换成十进制就是 83）、-0123（转换成十进制是 -83）。</p>
<p><em>注意：八进制必须以 0 开头</em></p>
<h4 id="十六进制"><a href="#十六进制" class="headerlink" title="十六进制"></a>十六进制</h4><p>如 0x25（转换成十进制数是 37）、0Xb1e（转换成十进制是 45086）</p>
<p><em>注意： 十六进制必须以 0X 或 0x 开头</em></p>
<p>整型数据根据它所占内存大小的不同，可分为 byte、short、int、long 4种类型，他们具有不同的取值范围，如下表所示。</p>
<table>
<thead>
<tr>
<th>数据类型</th>
<th>内存空间（8位=1字节）</th>
<th>取值范围</th>
</tr>
</thead>
<tbody>
<tr>
<td>byte</td>
<td>8位</td>
<td>-128～127</td>
</tr>
<tr>
<td>short</td>
<td>16位</td>
<td>-32768～32767</td>
</tr>
<tr>
<td>int</td>
<td>32位</td>
<td>-2147483648～2147483647</td>
</tr>
<tr>
<td>long</td>
<td>64位</td>
<td>-9223372036854775808～9223372036854775807</td>
</tr>
</tbody>
</table>
<p>下面以 int 型变量为例讲解整型变量的定义。</p>
<h4 id="定义-int-型变量，示例代码如下："><a href="#定义-int-型变量，示例代码如下：" class="headerlink" title="定义 int 型变量，示例代码如下："></a>定义 int 型变量，示例代码如下：</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">int</span> x; <span class="comment">//定义 int 型变量 x</span></span><br><span class="line"><span class="keyword">int</span> x,y;<span class="comment">//定义 int 型变量 x、y</span></span><br><span class="line"><span class="keyword">int</span> x = <span class="number">450</span>, y = -<span class="number">463</span>; <span class="comment">//定义 int 型变量 x、y 并赋初值</span></span><br></pre></td></tr></table></figure>
<p><em>注意1：定义以上 4 种类型变量时，需要注意变量的取值范围，超出相应范围就会出错。</em><br><em>注意2: 对于 long 型数值，若赋的初值大于 int 型的最大值或小于 int 型的最小值，则需要在数值后加 L 或 l，表示该值是长整型，如 <code>long num = 2147483650L</code>。</em></p>
<h4 id="运算操作，输出和"><a href="#运算操作，输出和" class="headerlink" title="运算操作，输出和"></a>运算操作，输出和</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Number</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">byte</span> mybyte = <span class="number">124</span>;</span><br><span class="line">        <span class="keyword">short</span> myshort = <span class="number">32564</span>;</span><br><span class="line">        <span class="keyword">int</span> myint = <span class="number">45784612</span>;</span><br><span class="line">        <span class="keyword">long</span> mylong = <span class="number">4678951</span>;</span><br><span class="line">        <span class="keyword">long</span> result = mybyte + myshort + myint + mylong;</span><br><span class="line">        System.out.println(<span class="string">"结果为："</span>+ result);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">程序运行结果为：</span><br><span class="line"></span><br><span class="line">结果为：<span class="number">92606751</span></span><br></pre></td></tr></table></figure>
<h3 id="浮点类型"><a href="#浮点类型" class="headerlink" title="浮点类型"></a>浮点类型</h3><p>浮点类型表示有小数部分的数字。Java 语言中浮点类型可分为单精度浮点类型（float）和双精度浮点型（double），它们具有不同的取值范围，如下表所示。</p>
<table>
<thead>
<tr>
<th>数据类型</th>
<th>内存空间（8位=1字节）</th>
<th>取值范围</th>
</tr>
</thead>
<tbody>
<tr>
<td>float</td>
<td>32位</td>
<td>1.4E-45～3.4028235E38</td>
</tr>
<tr>
<td>double</td>
<td>64位</td>
<td>4.9E-324～1.797693234862315E308</td>
</tr>
</tbody>
</table>
<p>在默认情况下，小数都被看作是 double 型，若使用 float 型小数，则需要在小数后面加上F或f。</p>
<h4 id="定义浮点类型变量，示例代码如下："><a href="#定义浮点类型变量，示例代码如下：" class="headerlink" title="定义浮点类型变量，示例代码如下："></a>定义浮点类型变量，示例代码如下：</h4><figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">float</span> f1 = <span class="number">13.23f</span>;</span><br><span class="line"><span class="keyword">double</span> d1 = <span class="number">354.12</span>d;</span><br><span class="line"><span class="keyword">double</span> d2 = <span class="number">23456.2345</span>;</span><br></pre></td></tr></table></figure>
<h3 id="字符类型"><a href="#字符类型" class="headerlink" title="字符类型"></a>字符类型</h3><h4 id="char-型"><a href="#char-型" class="headerlink" title="char 型"></a>char 型</h4><p>字符类型（char）用于存储单个字符，占用 16 位（两个字节）的内存空间。在定义字符型变量时，要以单引号表示，如 <code>&#39;s&#39;</code> 表示一个字符，而 <code>&quot;s&quot;</code>则表示一个字符串。</p>
<p>使用 <code>char</code> 关键字可定义字符变量，下面举例说明。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">char</span> x = <span class="string">'a'</span>;</span><br><span class="line"></span><br><span class="line">注意：字符 a 在 unicode 表中的排序位置是 <span class="number">97</span> ，所以上面的语句等同于：</span><br><span class="line"><span class="keyword">char</span> x = <span class="number">97</span>;</span><br></pre></td></tr></table></figure>
<p>同 c 和 C++ 语言一样，Java 语言也可以把字符作为整数对待。由于unicode 编码采用无符号编码，可以存储 65536 个字符（0x0000 ～ 0xffff），所以 Java 中的字符几乎可以处理所有国家的语言文字。</p>
<p><strong>在控制台输出 unicode 表中的字符以及在表中字符对应的位置</strong></p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">gess</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">char</span> word = <span class="string">'d'</span>, word2 = <span class="string">'@'</span>;</span><br><span class="line">        <span class="keyword">int</span> p = <span class="number">23045</span>, p2 = <span class="number">45213</span>;</span><br><span class="line">        System.out.println(<span class="string">"d 在 unicode 表中的顺序位置是："</span>+(<span class="keyword">int</span>)word);</span><br><span class="line">        System.out.println(<span class="string">"@ 在 unicode 表中的顺序位置是："</span>+(<span class="keyword">int</span>)word2);</span><br><span class="line">        System.out.println(<span class="string">"unicode 表中的第 23045 位是："</span>+(<span class="keyword">char</span>)p);</span><br><span class="line">        System.out.println(<span class="string">"unicode 表中的第 45213 位是："</span>+(<span class="keyword">char</span>)p2);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">输出结果为：</span><br><span class="line">d 在 unicode 表中的顺序位置是：<span class="number">100</span></span><br><span class="line">@ 在 unicode 表中的顺序位置是：<span class="number">64</span></span><br><span class="line">unicode 表中的第 <span class="number">23045</span> 位是：娅</span><br><span class="line">unicode 表中的第 <span class="number">45213</span> 位是： ?</span><br></pre></td></tr></table></figure>
<h4 id="转义字符"><a href="#转义字符" class="headerlink" title="转义字符"></a>转义字符</h4><p>转义字符是一种特殊的字符变量，它以反斜杠 <code>&quot;\&quot;</code> 开头，后跟一个或多个字符。转义字符具有特殊的含义，不同于字符原有的意义，故称 “转义”。Java 中的转义字符如下表所示：</p>
<table>
<thead>
<tr>
<th>转义字符</th>
<th>含义</th>
</tr>
</thead>
<tbody>
<tr>
<td>\ddd</td>
<td>1～3位八进制数所表示的字符，如\123</td>
</tr>
<tr>
<td>\uxxxx</td>
<td>4 位十六进制数所表示的字符，如 \u0052</td>
</tr>
<tr>
<td>\’</td>
<td>单引号字符</td>
</tr>
<tr>
<td>\</td>
<td>反斜杠字符</td>
</tr>
<tr>
<td>\t</td>
<td>垂直制表符，将光标移动下一个制表符的位置</td>
</tr>
<tr>
<td>\r</td>
<td>回车</td>
</tr>
<tr>
<td>\n</td>
<td>换行</td>
</tr>
<tr>
<td>\b</td>
<td>退格</td>
</tr>
<tr>
<td>\f</td>
<td>换页</td>
</tr>
</tbody>
</table>
<p>将转义字符赋值给字符变量时，与字符常量值一样需要使用单引号。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">char</span> c1 = <span class="string">'\\'</span>;</span><br><span class="line"><span class="keyword">char</span> char1 = <span class="string">"\u2605"</span>;</span><br><span class="line">System.out.println(c1);</span><br><span class="line">System.out.println(char1);</span><br></pre></td></tr></table></figure>
<h3 id="布尔类型"><a href="#布尔类型" class="headerlink" title="布尔类型"></a>布尔类型</h3><p>布尔类型又称逻辑类型，通过关键值 boolean 来定义布尔类型变量。只有 true 和 false 两个值，它们分别代表布尔逻辑中的 真 和 假。</p>
<p>布尔类型不能与整数类型进行转换。布尔类型通常被用在流程控制中作为判断条件。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">boolean</span> b;</span><br><span class="line"><span class="keyword">boolean</span> b1,b2;</span><br><span class="line"><span class="keyword">boolean</span> b = <span class="keyword">true</span>;</span><br></pre></td></tr></table></figure>


    
    
    
	  <div class="full-width auto-padding tags">
      
        <a href="/tags/Java/">Java</a>
      
	  </div>
    
  </section>
</article>
    </div>
  
    <div class='post-wrapper'>
      <article class="post reveal">
  <section class="meta">
    
    <h2 class="title">
      <a href="/2018/10/20/Java-面试题系列篇-编程大题/">
        Java 面试题系列篇-编程大题
      </a>
    </h2>
    
    <time>
      Oct 20, 2018
    </time>
		
  </section>
  <section class="article typo">
	  <h2 id="Java-编程题"><a href="#Java-编程题" class="headerlink" title="Java 编程题"></a>Java 编程题</h2><h3 id="如何读取eclipse中-src目录下的文件？至少两种"><a href="#如何读取eclipse中-src目录下的文件？至少两种" class="headerlink" title="如何读取eclipse中 src目录下的文件？至少两种"></a>如何读取eclipse中 src目录下的文件？至少两种</h3><p><a href="http://note.youdao.com/noteshare?id=f60ff6c6169c0f5211410a8ff3350000&amp;sub=8CA55EE3DA474C98A6C33F1988387FC6" target="_blank" rel="noopener">http://note.youdao.com/noteshare?id=f60ff6c6169c0f5211410a8ff3350000&amp;sub=8CA55EE3DA474C98A6C33F1988387FC6</a></p>
<h3 id="有两个list-集合怎么取无重复并集？"><a href="#有两个list-集合怎么取无重复并集？" class="headerlink" title="有两个list 集合怎么取无重复并集？"></a>有两个list 集合怎么取无重复并集？</h3><h3 id="如何将系统时间转化为-2017-5-28-格式？"><a href="#如何将系统时间转化为-2017-5-28-格式？" class="headerlink" title="如何将系统时间转化为 2017/5/28 格式？"></a>如何将系统时间转化为 2017/5/28 格式？</h3><p><a href="http://note.youdao.com/noteshare?id=b634c901a7b2739d3d9c439c57ce99b8&amp;sub=34424049F77F421E9249AE3622E4A8DE" target="_blank" rel="noopener">http://note.youdao.com/noteshare?id=b634c901a7b2739d3d9c439c57ce99b8&amp;sub=34424049F77F421E9249AE3622E4A8DE</a></p>
<h3 id="页面二级级联菜单如何实现？如-第一个下拉列表为省，第二个下拉列表为市。"><a href="#页面二级级联菜单如何实现？如-第一个下拉列表为省，第二个下拉列表为市。" class="headerlink" title="页面二级级联菜单如何实现？如 第一个下拉列表为省，第二个下拉列表为市。"></a>页面二级级联菜单如何实现？如 第一个下拉列表为省，第二个下拉列表为市。</h3><h3 id="请简述如何模拟实现-IOC-和-DI？-代码或者具体细节步骤？"><a href="#请简述如何模拟实现-IOC-和-DI？-代码或者具体细节步骤？" class="headerlink" title="请简述如何模拟实现 IOC 和 DI？ 代码或者具体细节步骤？"></a>请简述如何模拟实现 IOC 和 DI？ 代码或者具体细节步骤？</h3>

    
    
    
	  <div class="full-width auto-padding tags">
      
        <a href="/tags/Java/">Java</a>
      
	  </div>
    
  </section>
</article>
    </div>
  
    <div class='post-wrapper'>
      <article class="post reveal">
  <section class="meta">
    
    <h2 class="title">
      <a href="/2018/10/20/Java-面试题系列篇-虚拟机/">
        Java 面试题系列篇-虚拟机
      </a>
    </h2>
    
    <time>
      Oct 20, 2018
    </time>
		
  </section>
  <section class="article typo">
	  <h2 id="虚拟机-（JVM）"><a href="#虚拟机-（JVM）" class="headerlink" title="虚拟机 （JVM）"></a>虚拟机 （JVM）</h2><h3 id="【JVM】你知道哪些或者你们线上使⽤什么GC策略？它有什么优势，适⽤于什么场景？"><a href="#【JVM】你知道哪些或者你们线上使⽤什么GC策略？它有什么优势，适⽤于什么场景？" class="headerlink" title="【JVM】你知道哪些或者你们线上使⽤什么GC策略？它有什么优势，适⽤于什么场景？"></a>【JVM】<strong>你知道哪些或者你们线上使⽤什么GC策略？它有什么优势，适⽤于什么场景？</strong></h3><p><a href="https://blog.csdn.net/chenleixing/article/details/46706039/" target="_blank" rel="noopener">https://blog.csdn.net/chenleixing/article/details/46706039/</a></p>
<h3 id="【JVM】Java类加载器包括⼏种？它们之间的⽗⼦关系是怎么样的？双亲委派机制是什么意思？有什么好处？"><a href="#【JVM】Java类加载器包括⼏种？它们之间的⽗⼦关系是怎么样的？双亲委派机制是什么意思？有什么好处？" class="headerlink" title="【JVM】Java类加载器包括⼏种？它们之间的⽗⼦关系是怎么样的？双亲委派机制是什么意思？有什么好处？"></a>【JVM】<strong>Java类加载器包括⼏种？它们之间的⽗⼦关系是怎么样的？双亲委派机制是什么意思？有什么好处？</strong></h3><p>启动Bootstrap类加载、扩展Extension类加载、系统System类加载。</p>
<p>父子关系如下：</p>
<p>启动类加载器 ，由C++ 实现，没有父类；</p>
<p>扩展类加载器，由Java语言实现，父类加载器为null；</p>
<p>系统类加载器，由Java语言实现，父类加载器为扩展类加载器；</p>
<p>自定义类加载器，父类加载器肯定为AppClassLoader。</p>
<p>双亲委派机制：类加载器收到类加载请求，自己不加载，向上委托给父类加载，父类加载不了，再自己加载。</p>
<p>优势避免Java核心API篡改。</p>
<p><a href="https://blog.csdn.net/javazejian/article/details/73413292/" target="_blank" rel="noopener">https://blog.csdn.net/javazejian/article/details/73413292/</a></p>
<h3 id="【JVM】如何⾃定义⼀个类加载器？你使⽤过哪些或者你在什么场景下需要⼀个⾃定义的类加载器吗？"><a href="#【JVM】如何⾃定义⼀个类加载器？你使⽤过哪些或者你在什么场景下需要⼀个⾃定义的类加载器吗？" class="headerlink" title="【JVM】如何⾃定义⼀个类加载器？你使⽤过哪些或者你在什么场景下需要⼀个⾃定义的类加载器吗？"></a>【JVM】<strong>如何⾃定义⼀个类加载器？你使⽤过哪些或者你在什么场景下需要⼀个⾃定义的类加载器吗？</strong></h3><p>自定义类加载的意义：</p>
<p>加载特定路径的class文件</p>
<p>加载一个加密的网络class文件</p>
<p>热部署加载class文件</p>
<h3 id="【JVM】jstack-是⼲什么的-jstat-呢？如果线上程序周期性地出现卡顿，你怀疑可-能是-GC-导致的，你会怎么来排查这个问题？线程⽇志⼀般你会看其中的什么-部分？"><a href="#【JVM】jstack-是⼲什么的-jstat-呢？如果线上程序周期性地出现卡顿，你怀疑可-能是-GC-导致的，你会怎么来排查这个问题？线程⽇志⼀般你会看其中的什么-部分？" class="headerlink" title="【JVM】jstack 是⼲什么的? jstat 呢？如果线上程序周期性地出现卡顿，你怀疑可 能是 GC 导致的，你会怎么来排查这个问题？线程⽇志⼀般你会看其中的什么 部分？"></a>【JVM】<strong>jstack 是⼲什么的? jstat 呢？如果线上程序周期性地出现卡顿，你怀疑可 能是 GC 导致的，你会怎么来排查这个问题？线程⽇志⼀般你会看其中的什么 部分？</strong></h3><p>jstack 用来查询 Java 进程的堆栈信息。</p>
<p>jvisualvm 监控内存泄露，跟踪垃圾回收、执行时内存、cpu分析、线程分析。</p>
<p>详见Java jvisualvm简要说明，可参考 线上FullGC频繁的排查。</p>
<p>Java jvisualvm简要说明</p>
<p><a href="https://blog.csdn.net/a19881029/article/details/8432368/" target="_blank" rel="noopener">https://blog.csdn.net/a19881029/article/details/8432368/</a></p>
<p>线上FullGC频繁的排查</p>
<p><a href="https://blog.csdn.net/wilsonpeng3/article/details/70064336/" target="_blank" rel="noopener">https://blog.csdn.net/wilsonpeng3/article/details/70064336/</a></p>
<h3 id="【JVM】StackOverflow异常有没有遇到过？⼀般你猜测会在什么情况下被触发？如何指定⼀个线程的堆栈⼤⼩？⼀般你们写多少？"><a href="#【JVM】StackOverflow异常有没有遇到过？⼀般你猜测会在什么情况下被触发？如何指定⼀个线程的堆栈⼤⼩？⼀般你们写多少？" class="headerlink" title="【JVM】StackOverflow异常有没有遇到过？⼀般你猜测会在什么情况下被触发？如何指定⼀个线程的堆栈⼤⼩？⼀般你们写多少？"></a>【JVM】<strong>StackOverflow异常有没有遇到过？⼀般你猜测会在什么情况下被触发？如何指定⼀个线程的堆栈⼤⼩？⼀般你们写多少？</strong></h3><p>栈内存溢出，一般由栈内存的局部变量过爆了，导致内存溢出。出现在递归方法，参数个数过多，递归过深，递归没有出口。</p>
<h3 id="什么是垃圾回收？"><a href="#什么是垃圾回收？" class="headerlink" title="什么是垃圾回收？"></a>什么是垃圾回收？</h3><p>垃圾回收是Java中自动内存管理的另一种叫法。垃圾回收的目的是为程序保持尽可能多的可用堆（heap）。 JVM会删除堆上不再需要从堆引用的对象。</p>
<h3 id="用一个例子解释垃圾回收？"><a href="#用一个例子解释垃圾回收？" class="headerlink" title="用一个例子解释垃圾回收？"></a>用一个例子解释垃圾回收？</h3><p>比方说，下面这个方法就会从函数调用。</p>
<p>void method(){</p>
<p>​    Calendar calendar = new GregorianCalendar(2000,10,30);</p>
<p>​    System.out.println(calendar);</p>
<p>}</p>
<p>通过函数第一行代码中参考变量calendar，在堆上创建了GregorianCalendar类的一个对象。</p>
<p>函数结束执行后，引用变量calendar不再有效。因此，在方法中没有创建引用到对象。</p>
<p>JVM认识到这一点，会从堆中删除对象。这就是所谓的垃圾回收。</p>
<h3 id="什么时候运行垃圾回收？"><a href="#什么时候运行垃圾回收？" class="headerlink" title="什么时候运行垃圾回收？"></a>什么时候运行垃圾回收？</h3><p>垃圾回收在JVM突发奇想和心血来潮时运行（没有那么糟糕）。运行垃圾收集的可能情况是：</p>
<p>堆可用内存不足</p>
<p>CPU空闲</p>
<h3 id="垃圾回收的最佳做法？"><a href="#垃圾回收的最佳做法？" class="headerlink" title="垃圾回收的最佳做法？"></a>垃圾回收的最佳做法？</h3><p>用编程的方式，我们可以要求（记住这只是一个请求——不是一个命令）JVM通过调用System.gc()方法来运行垃圾回收。</p>
<p>当内存已满，且堆上没有对象可用于垃圾回收时，JVM可能会抛出OutOfMemoryException。</p>
<p>对象在被垃圾回收从堆上删除之前，会运行finalize()方法。我们建议不要用finalize()方法写任何代码。</p>
<h3 id="Java-中会存在内存泄漏吗，请简单描述。"><a href="#Java-中会存在内存泄漏吗，请简单描述。" class="headerlink" title="Java 中会存在内存泄漏吗，请简单描述。"></a>Java 中会存在内存泄漏吗，请简单描述。</h3><p>答：理论上Java因为有垃圾回收机制（GC）不会存在内存泄露问题（这也是Java被广泛使用于服务器端编程的一个重要原因）；然而在实际开发中，可能会存在无用但可达的对象，这些对象不能被GC回收，因此也会导致内存泄露的发生。例如Hibernate的Session（一级缓存）中的对象属于持久态，垃圾回收器是不会回收这些对象的，然而这些对象中可能存在无用的垃圾对象，如果不及时关闭（close）或清空（flush）一级缓存就可能导致内存泄露。下面例子中的代码也会导致内存泄露。</p>
<p>import java.util.Arrays;</p>
<p>import java.util.EmptyStackException;</p>
<p>public class MyStack<t> {</t></p>
<p>​    private T[] elements;</p>
<p>​    private int size = 0;</p>
<p>​    private static final int INIT_CAPACITY = 16;</p>
<p>​    public MyStack() {</p>
<p>​        elements = (T[]) new Object[INIT_CAPACITY];</p>
<p>​    }</p>
<p>​    public void push(T elem) {</p>
<p>​        ensureCapacity();</p>
<p>​        elements[size++] = elem;</p>
<p>​    }</p>
<p>​    public T pop() {</p>
<p>​        if(size == 0) </p>
<p>​            throw new EmptyStackException();</p>
<p>​        return elements[–size];</p>
<p>​    }</p>
<p>​    private void ensureCapacity() {</p>
<p>​        if(elements.length == size) {</p>
<p>​            elements = Arrays.copyOf(elements, 2 * size + 1);</p>
<p>​        }</p>
<p>​    }</p>
<p>}</p>
<p>上面的代码实现了一个栈（先进后出（FILO））结构，乍看之下似乎没有什么明显的问题，它甚至可以通过你编写的各种单元测试。然而其中的pop方法却存在内存泄露的问题，当我们用pop方法弹出栈中的对象时，该对象不会被当作垃圾回收，即使使用栈的程序不再引用这些对象，因为栈内部维护着对这些对象的过期引用（obsolete reference）。在支持垃圾回收的语言中，内存泄露是很隐蔽的，这种内存泄露其实就是无意识的对象保持。如果一个对象引用被无意识的保留起来了，那么垃圾回收器不会处理这个对象，也不会处理该对象引用的其他对象，即使这样的对象只有少数几个，也可能会导致很多的对象被排除在垃圾回收之外，从而对性能造成重大影响，极端情况下会引发Disk Paging（物理内存与硬盘的虚拟内存交换数据），甚至造成OutOfMemoryError。</p>
<h3 id="GC是什么？为什么要有GC？"><a href="#GC是什么？为什么要有GC？" class="headerlink" title="GC是什么？为什么要有GC？"></a>GC是什么？为什么要有GC？</h3><p>答：GC是垃圾收集的意思，内存处理是编程人员容易出现问题的地方，忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃，Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的，Java语言没有提供释放已分配内存的显示操作方法。Java程序员不用担心内存管理，因为垃圾收集器会自动进行管理。要请求垃圾收集，可以调用下面的方法之一：System.gc() 或Runtime.getRuntime().gc() ，但JVM可以屏蔽掉显示的垃圾回收调用。<br>垃圾回收可以有效的防止内存泄露，有效的使用可以使用的内存。垃圾回收器通常是作为一个单独的低优先级的线程运行，不可预知的情况下对内存堆中已经死亡的或者长时间没有使用的对象进行清除和回收，程序员不能实时的调用垃圾回收器对某个对象或所有对象进行垃圾回收。在Java诞生初期，垃圾回收是Java最大的亮点之一，因为服务器端的编程需要有效的防止内存泄露问题，然而时过境迁，如今Java的垃圾回收机制已经成为被诟病的东西。移动智能终端用户通常觉得iOS的系统比Android系统有更好的用户体验，其中一个深层次的原因就在于Android系统中垃圾回收的不可预知性。</p>
<p>补充：垃圾回收机制有很多种，包括：分代复制垃圾回收、标记垃圾回收、增量垃圾回收等方式。标准的Java进程既有栈又有堆。栈保存了原始型局部变量，堆保存了要创建的对象。Java平台对堆内存回收和再利用的基本算法被称为标记和清除，但是Java对其进行了改进，采用“分代式垃圾收集”。这种方法会跟Java对象的生命周期将堆内存划分为不同的区域，在垃圾收集过程中，可能会将对象移动到不同区域： </p>
<ul>
<li>伊甸园（Eden）：这是对象最初诞生的区域，并且对大多数对象来说，这里是它们唯一存在过的区域。 </li>
<li>幸存者乐园（Survivor）：从伊甸园幸存下来的对象会被挪到这里。 </li>
<li>终身颐养园（Tenured）：这是足够老的幸存对象的归宿。年轻代收集（Minor-GC）过程是不会触及这个地方的。当年轻代收集不能把对象放进终身颐养园时，就会触发一次完全收集（Major-GC），这里可能还会牵扯到压缩，以便为大对象腾出足够的空间。</li>
</ul>
<p>与垃圾回收相关的JVM参数：</p>
<p>-Xms / -Xmx — 堆的初始大小 / 堆的最大大小</p>
<p>-Xmn — 堆中年轻代的大小</p>
<p>-XX:-DisableExplicitGC — 让System.gc()不产生任何作用</p>
<p>-XX:+PrintGCDetails — 打印GC的细节</p>
<p>-XX:+PrintGCDateStamps — 打印GC操作的时间戳</p>
<p>-XX:NewSize / XX:MaxNewSize — 设置新生代大小/新生代最大大小</p>
<p>-XX:NewRatio — 可以设置老生代和新生代的比例</p>
<p>-XX:PrintTenuringDistribution — 设置每次新生代GC后输出幸存者乐园中对象年龄的分布</p>
<p>-XX:InitialTenuringThreshold / -XX:MaxTenuringThreshold：设置老年代阀值的初始值和最大值</p>
<p>-XX:TargetSurvivorRatio：设置幸存区的目标使用率</p>


    
    
    
	  <div class="full-width auto-padding tags">
      
        <a href="/tags/Java/">Java</a>
      
	  </div>
    
  </section>
</article>
    </div>
  
    <div class='post-wrapper'>
      <article class="post reveal">
  <section class="meta">
    
    <h2 class="title">
      <a href="/2018/10/20/Java-面试题系列篇-SpringMVC-框架/">
        Java 面试题系列篇-SpringMVC 框架
      </a>
    </h2>
    
    <time>
      Oct 20, 2018
    </time>
		
  </section>
  <section class="article typo">
	  <h2 id="SpringMVC-框架"><a href="#SpringMVC-框架" class="headerlink" title="SpringMVC 框架"></a>SpringMVC 框架</h2><h3 id="如何在Web项目中配置Spring-MVC？"><a href="#如何在Web项目中配置Spring-MVC？" class="headerlink" title="如何在Web项目中配置Spring MVC？"></a>如何在Web项目中配置Spring MVC？</h3><p>答：要使用Spring MVC需要在Web项目配置文件中配置其前端控制器DispatcherServlet，如下所示：</p>
<p><web-app></web-app></p>
<p>​    <servlet></servlet></p>
<p>​        <servlet-name>example</servlet-name></p>
<p>​        <servlet-class></servlet-class></p>
<p>​            org.springframework.web.servlet.DispatcherServlet</p>
<p>​        </p>
<p>​        <load-on-startup>1</load-on-startup></p>
<p>​    </p>
<p>​    <servlet-mapping></servlet-mapping></p>
<p>​        <servlet-name>example</servlet-name></p>
<p>​        <url-pattern>*.html</url-pattern></p>
<p>​    </p>
<p></p>
<p>说明：上面的配置中使用了*.html的后缀映射，这样做一方面不能够通过URL推断采用了何种服务器端的技术，另一方面可以欺骗搜索引擎，因为搜索引擎不会搜索动态页面，这种做法称为伪静态化。</p>
<h3 id="Spring-MVC的工作原理是怎样的？"><a href="#Spring-MVC的工作原理是怎样的？" class="headerlink" title="Spring MVC的工作原理是怎样的？"></a>Spring MVC的工作原理是怎样的？</h3><p>答：Spring MVC的工作原理如下图所示：<br>① 客户端的所有请求都交给前端控制器DispatcherServlet来处理，它会负责调用系统的其他模块来真正处理用户的请求。<br>② DispatcherServlet收到请求后，将根据请求的信息（包括URL、HTTP协议方法、请求头、请求参数、Cookie等）以及HandlerMapping的配置找到处理该请求的Handler（任何一个对象都可以作为请求的Handler）。<br>③在这个地方Spring会通过HandlerAdapter对该处理器进行封装。<br>④ HandlerAdapter是一个适配器，它用统一的接口对各种Handler中的方法进行调用。<br>⑤ Handler完成对用户请求的处理后，会返回一个ModelAndView对象给DispatcherServlet，ModelAndView顾名思义，包含了数据模型以及相应的视图的信息。<br>⑥ ModelAndView的视图是逻辑视图，DispatcherServlet还要借助ViewResolver完成从逻辑视图到真实视图对象的解析工作。<br>⑦ 当得到真正的视图对象后，DispatcherServlet会利用视图对象对模型数据进行渲染。<br>⑧ 客户端得到响应，可能是一个普通的HTML页面，也可以是XML或JSON字符串，还可以是一张图片或者一个PDF文件。</p>
<h3 id="大型网站在架构上应当考虑哪些问题？"><a href="#大型网站在架构上应当考虑哪些问题？" class="headerlink" title="大型网站在架构上应当考虑哪些问题？"></a>大型网站在架构上应当考虑哪些问题？</h3><p>答： </p>
<ul>
<li>分层：分层是处理任何复杂系统最常见的手段之一，将系统横向切分成若干个层面，每个层面只承担单一的职责，然后通过下层为上层提供的基础设施和服务以及上层对下层的调用来形成一个完整的复杂的系统。计算机网络的开放系统互联参考模型（OSI/RM）和Internet的TCP/IP模型都是分层结构，大型网站的软件系统也可以使用分层的理念将其分为持久层（提供数据存储和访问服务）、业务层（处理业务逻辑，系统中最核心的部分）和表示层（系统交互、视图展示）。需要指出的是：（1）分层是逻辑上的划分，在物理上可以位于同一设备上也可以在不同的设备上部署不同的功能模块，这样可以使用更多的计算资源来应对用户的并发访问；（2）层与层之间应当有清晰的边界，这样分层才有意义，才更利于软件的开发和维护。 </li>
<li>分割：分割是对软件的纵向切分。我们可以将大型网站的不同功能和服务分割开，形成高内聚低耦合的功能模块（单元）。在设计初期可以做一个粗粒度的分割，将网站分割为若干个功能模块，后期还可以进一步对每个模块进行细粒度的分割，这样一方面有助于软件的开发和维护，另一方面有助于分布式的部署，提供网站的并发处理能力和功能的扩展。 </li>
<li>分布式：除了上面提到的内容，网站的静态资源（JavaScript、CSS、图片等）也可以采用独立分布式部署并采用独立的域名，这样可以减轻应用服务器的负载压力，也使得浏览器对资源的加载更快。数据的存取也应该是分布式的，传统的商业级关系型数据库产品基本上都支持分布式部署，而新生的NoSQL产品几乎都是分布式的。当然，网站后台的业务处理也要使用分布式技术，例如查询索引的构建、数据分析等，这些业务计算规模庞大，可以使用Hadoop以及MapReduce分布式计算框架来处理。 </li>
<li>集群：集群使得有更多的服务器提供相同的服务，可以更好的提供对并发的支持。 </li>
<li>缓存：所谓缓存就是用空间换取时间的技术，将数据尽可能放在距离计算最近的位置。使用缓存是网站优化的第一定律。我们通常说的CDN、反向代理、热点数据都是对缓存技术的使用。 </li>
<li>异步：异步是实现软件实体之间解耦合的又一重要手段。异步架构是典型的生产者消费者模式，二者之间没有直接的调用关系，只要保持数据结构不变，彼此功能实现可以随意变化而不互相影响，这对网站的扩展非常有利。使用异步处理还可以提高系统可用性，加快网站的响应速度（用Ajax加载数据就是一种异步技术），同时还可以起到削峰作用（应对瞬时高并发）。”；能推迟处理的都要推迟处理”是网站优化的第二定律，而异步是践行网站优化第二定律的重要手段。 </li>
<li>冗余：各种服务器都要提供相应的冗余服务器以便在某台或某些服务器宕机时还能保证网站可以正常工作，同时也提供了灾难恢复的可能性。冗余是网站高可用性的重要保证。</li>
</ul>
<h3 id="你用过的网站前端优化的技术有哪些？"><a href="#你用过的网站前端优化的技术有哪些？" class="headerlink" title="你用过的网站前端优化的技术有哪些？"></a>你用过的网站前端优化的技术有哪些？</h3><p>答：<br>① 浏览器访问优化： </p>
<ul>
<li>减少HTTP请求数量：合并CSS、合并JavaScript、合并图片（CSS Sprite） </li>
<li>使用浏览器缓存：通过设置HTTP响应头中的Cache-Control和Expires属性，将CSS、JavaScript、图片等在浏览器中缓存，当这些静态资源需要更新时，可以更新HTML文件中的引用来让浏览器重新请求新的资源 </li>
<li>启用压缩 </li>
<li>CSS前置，JavaScript后置 </li>
<li>减少Cookie传输<br>② CDN加速：CDN（Content Distribute Network）的本质仍然是缓存，将数据缓存在离用户最近的地方，CDN通常部署在网络运营商的机房，不仅可以提升响应速度，还可以减少应用服务器的压力。当然，CDN缓存的通常都是静态资源。<br>③ 反向代理：反向代理相当于应用服务器的一个门面，可以保护网站的安全性，也可以实现负载均衡的功能，当然最重要的是它缓存了用户访问的热点资源，可以直接从反向代理将某些内容返回给用户浏览器。</li>
</ul>
<h3 id="你使用过的应用服务器优化技术有哪些？"><a href="#你使用过的应用服务器优化技术有哪些？" class="headerlink" title="你使用过的应用服务器优化技术有哪些？"></a>你使用过的应用服务器优化技术有哪些？</h3><p>答：<br>① 分布式缓存：缓存的本质就是内存中的哈希表，如果设计一个优质的哈希函数，那么理论上哈希表读写的渐近时间复杂度为O(1)。缓存主要用来存放那些读写比很高、变化很少的数据，这样应用程序读取数据时先到缓存中读取，如果没有或者数据已经失效再去访问数据库或文件系统，并根据拟定的规则将数据写入缓存。对网站数据的访问也符合二八定律（Pareto分布，幂律分布），即80%的访问都集中在20%的数据上，如果能够将这20%的数据缓存起来，那么系统的性能将得到显著的改善。当然，使用缓存需要解决以下几个问题： </p>
<ul>
<li>频繁修改的数据； </li>
<li>数据不一致与脏读； </li>
<li>缓存雪崩（可以采用分布式缓存服务器集群加以解决，memcached是广泛采用的解决方案）； </li>
<li>缓存预热； </li>
<li>缓存穿透（恶意持续请求不存在的数据）。<br>② 异步操作：可以使用消息队列将调用异步化，通过异步处理将短时间高并发产生的事件消息存储在消息队列中，从而起到削峰作用。电商网站在进行促销活动时，可以将用户的订单请求存入消息队列，这样可以抵御大量的并发订单请求对系统和数据库的冲击。目前，绝大多数的电商网站即便不进行促销活动，订单系统都采用了消息队列来处理。<br>③ 使用集群。<br>④ 代码优化： </li>
<li>多线程：基于Java的Web开发基本上都通过多线程的方式响应用户的并发请求，使用多线程技术在编程上要解决线程安全问题，主要可以考虑以下几个方面：A. 将对象设计为无状态对象（这和面向对象的编程观点是矛盾的，在面向对象的世界中被视为不良设计），这样就不会存在并发访问时对象状态不一致的问题。B. 在方法内部创建对象，这样对象由进入方法的线程创建，不会出现多个线程访问同一对象的问题。使用ThreadLocal将对象与线程绑定也是很好的做法，这一点在前面已经探讨过了。C. 对资源进行并发访问时应当使用合理的锁机制。 </li>
<li>非阻塞I/O： 使用单线程和非阻塞I/O是目前公认的比多线程的方式更能充分发挥服务器性能的应用模式，基于Node.js构建的服务器就采用了这样的方式。Java在JDK 1.4中就引入了NIO（Non-blocking I/O）,在Servlet 3规范中又引入了异步Servlet的概念，这些都为在服务器端采用非阻塞I/O提供了必要的基础。 </li>
<li>资源复用：资源复用主要有两种方式，一是单例，二是对象池，我们使用的数据库连接池、线程池都是对象池化技术，这是典型的用空间换取时间的策略，另一方面也实现对资源的复用，从而避免了不必要的创建和释放资源所带来的开销。</li>
</ul>
<h3 id="什么是XSS攻击？什么是SQL注入攻击？什么是CSRF攻击？"><a href="#什么是XSS攻击？什么是SQL注入攻击？什么是CSRF攻击？" class="headerlink" title="什么是XSS攻击？什么是SQL注入攻击？什么是CSRF攻击？"></a>什么是XSS攻击？什么是SQL注入攻击？什么是CSRF攻击？</h3><p> 答： </p>
<ul>
<li>XSS（Cross Site Script，跨站脚本攻击）是向网页中注入恶意脚本在用户浏览网页时在用户浏览器中执行恶意脚本的攻击方式。跨站脚本攻击分有两种形式：反射型攻击（诱使用户点击一个嵌入恶意脚本的链接以达到攻击的目标，目前有很多攻击者利用论坛、微博发布含有恶意脚本的URL就属于这种方式）和持久型攻击（将恶意脚本提交到被攻击网站的数据库中，用户浏览网页时，恶意脚本从数据库中被加载到页面执行，QQ邮箱的早期版本就曾经被利用作为持久型跨站脚本攻击的平台）。XSS虽然不是什么新鲜玩意，但是攻击的手法却不断翻新，防范XSS主要有两方面：消毒（对危险字符进行转义）和HttpOnly（防范XSS攻击者窃取Cookie数据）。 </li>
<li>SQL注入攻击是注入攻击最常见的形式（此外还有OS注入攻击（Struts 2的高危漏洞就是通过OGNL实施OS注入攻击导致的）），当服务器使用请求参数构造SQL语句时，恶意的SQL被嵌入到SQL中交给数据库执行。SQL注入攻击需要攻击者对数据库结构有所了解才能进行，攻击者想要获得表结构有多种方式：（1）如果使用开源系统搭建网站，数据库结构也是公开的（目前有很多现成的系统可以直接搭建论坛，电商网站，虽然方便快捷但是风险是必须要认真评估的）；（2）错误回显（如果将服务器的错误信息直接显示在页面上，攻击者可以通过非法参数引发页面错误从而通过错误信息了解数据库结构，Web应用应当设置友好的错误页，一方面符合最小惊讶原则，一方面屏蔽掉可能给系统带来危险的错误回显信息）；（3）盲注。防范SQL注入攻击也可以采用消毒的方式，通过正则表达式对请求参数进行验证，此外，参数绑定也是很好的手段，这样恶意的SQL会被当做SQL的参数而不是命令被执行，JDBC中的PreparedStatement就是支持参数绑定的语句对象，从性能和安全性上都明显优于Statement。 </li>
<li>CSRF攻击（Cross Site Request Forgery，跨站请求伪造）是攻击者通过跨站请求，以合法的用户身份进行非法操作（如转账或发帖等）。CSRF的原理是利用浏览器的Cookie或服务器的Session，盗取用户身份，其原理如下图所示。防范CSRF的主要手段是识别请求者的身份，主要有以下几种方式：（1）在表单中添加令牌（token）；（2）验证码；（3）检查请求头中的Referer（前面提到防图片盗链接也是用的这种方式）。令牌和验证都具有一次消费性的特征，因此在原理上一致的，但是验证码是一种糟糕的用户体验，不是必要的情况下不要轻易使用验证码，目前很多网站的做法是如果在短时间内多次提交一个表单未获得成功后才要求提供验证码，这样会获得较好的用户体验。</li>
</ul>
<p>补充：防火墙的架设是Web安全的重要保障，ModSecurity是开源的Web防火墙中的佼佼者。企业级防火墙的架设应当有两级防火墙，Web服务器和部分应用服务器可以架设在两级防火墙之间的DMZ，而数据和资源服务器应当架设在第二级防火墙之后。</p>
<h3 id="什么是领域模型-domain-model-？贫血模型-anaemic-domain-model-和充血模型-rich-domain-model-有什么区别？"><a href="#什么是领域模型-domain-model-？贫血模型-anaemic-domain-model-和充血模型-rich-domain-model-有什么区别？" class="headerlink" title="什么是领域模型(domain model)？贫血模型(anaemic domain model)和充血模型(rich domain model)有什么区别？"></a>什么是领域模型(domain model)？贫血模型(anaemic domain model)和充血模型(rich domain model)有什么区别？</h3><p>答：领域模型是领域内的概念类或现实世界中对象的可视化表示，又称为概念模型或分析对象模型，它专注于分析问题领域本身，发掘重要的业务领域概念，并建立业务领域概念之间的关系。贫血模型是指使用的领域对象中只有setter和getter方法（POJO），所有的业务逻辑都不包含在领域对象中而是放在业务逻辑层。有人将我们这里说的贫血模型进一步划分成失血模型（领域对象完全没有业务逻辑）和贫血模型（领域对象有少量的业务逻辑），我们这里就不对此加以区分了。充血模型将大多数业务逻辑和持久化放在领域对象中，业务逻辑（业务门面）只是完成对业务逻辑的封装、事务和权限等的处理。下面两张图分别展示了贫血模型和充血模型的分层架构。</p>
<p>贫血模型 </p>
<p>充血模型 </p>
<p>贫血模型下组织领域逻辑通常使用事务脚本模式，让每个过程对应用户可能要做的一个动作，每个动作由一个过程来驱动。也就是说在设计业务逻辑接口的时候，每个方法对应着用户的一个操作，这种模式有以下几个有点： </p>
<ul>
<li>它是一个大多数开发者都能够理解的简单过程模型（适合国内的绝大多数开发者）。 </li>
<li>它能够与一个使用行数据入口或表数据入口的简单数据访问层很好的协作。 </li>
<li>事务边界的显而易见，一个事务开始于脚本的开始，终止于脚本的结束，很容易通过代理（或切面）实现声明式事务。<br>然而，事务脚本模式的缺点也是很多的，随着领域逻辑复杂性的增加，系统的复杂性将迅速增加，程序结构将变得极度混乱。开源中国社区上有一篇很好的译文《贫血领域模型是如何导致糟糕的软件产生》对这个问题做了比较细致的阐述。</li>
</ul>
<h3 id="谈一谈测试驱动开发（TDD）的好处以及你的理解。"><a href="#谈一谈测试驱动开发（TDD）的好处以及你的理解。" class="headerlink" title="谈一谈测试驱动开发（TDD）的好处以及你的理解。"></a>谈一谈测试驱动开发（TDD）的好处以及你的理解。</h3><p>答：TDD是指在编写真正的功能实现代码之前先写测试代码，然后根据需要重构实现代码。在JUnit的作者Kent Beck的大作《测试驱动开发：实战与模式解析》（Test-Driven Development: by Example）一书中有这么一段内容：“消除恐惧和不确定性是编写测试驱动代码的重要原因”。因为编写代码时的恐惧会让你小心试探，让你回避沟通，让你羞于得到反馈，让你变得焦躁不安，而TDD是消除恐惧、让Java开发者更加自信更加乐于沟通的重要手段。TDD会带来的好处可能不会马上呈现，但是你在某个时候一定会发现，这些好处包括： </p>
<ul>
<li>更清晰的代码 — 只写需要的代码 </li>
<li>更好的设计 </li>
<li>更出色的灵活性 — 鼓励程序员面向接口编程 </li>
<li>更快速的反馈 — 不会到系统上线时才知道bug的存在</li>
</ul>
<p>补充：敏捷软件开发的概念已经有很多年了，而且也部分的改变了软件开发这个行业，TDD也是敏捷开发所倡导的。</p>
<p>TDD可以在多个层级上应用，包括单元测试（测试一个类中的代码）、集成测试（测试类之间的交互）、系统测试（测试运行的系统）和系统集成测试（测试运行的系统包括使用的第三方组件）。TDD的实施步骤是：红（失败测试）- 绿（通过测试） - 重构。关于实施TDD的详细步骤请参考另一篇文章《测试驱动开发之初窥门径》。<br>在使用TDD开发时，经常会遇到需要被测对象需要依赖其他子系统的情况，但是你希望将测试代码跟依赖项隔离，以保证测试代码仅仅针对当前被测对象或方法展开，这时候你需要的是测试替身。测试替身可以分为四类： </p>
<ul>
<li>虚设替身：只传递但是不会使用到的对象，一般用于填充方法的参数列表 </li>
<li>存根替身：总是返回相同的预设响应，其中可能包括一些虚设状态 </li>
<li>伪装替身：可以取代真实版本的可用版本（比真实版本还是会差很多） </li>
<li>模拟替身：可以表示一系列期望值的对象，并且可以提供预设响应<br>Java世界中实现模拟替身的第三方工具非常多，包括EasyMock、Mockito、jMock等。</li>
</ul>
<h3 id="什么是可变参数？"><a href="#什么是可变参数？" class="headerlink" title="什么是可变参数？"></a>什么是可变参数？</h3><p>可变参数允许调用参数数量不同的方法。请看下面例子中的求和方法。此方法可以调用1个int参数，或2个int参数，或多个int参数。</p>
<p> //int(type) followed … (three dot’s) is syntax of a variable argument. </p>
<p>​    public int sum(int… numbers) {</p>
<p>​        //inside the method a variable argument is similar to an array.</p>
<p>​        //number can be treated as if it is declared as int[] numbers;</p>
<p>​        int sum = 0;</p>
<p>​        for (int number: numbers) {</p>
<p>​            sum += number;</p>
<p>​        }</p>
<p>​        return sum;</p>
<p>​    }</p>
<p>​    public static void main(String[] args) {</p>
<p>​        VariableArgumentExamples example = new VariableArgumentExamples();</p>
<p>​        //3 Arguments</p>
<p>​        System.out.println(example.sum(1, 4, 5));//10</p>
<p>​        //4 Arguments</p>
<p>​        System.out.println(example.sum(1, 4, 5, 20));//30</p>
<p>​        //0 Arguments</p>
<p>​        System.out.println(example.sum());//0</p>
<p>}</p>
<h3 id="断言的用途？"><a href="#断言的用途？" class="headerlink" title="断言的用途？"></a>断言的用途？</h3><p>断言是在Java 1.4中引入的。它能让你验证假设。如果断言失败（即返回false），就会抛出AssertionError（如果启用断言）。基本断言如下所示。</p>
<p>private int computerSimpleInterest(int principal,float interest,int years){</p>
<p>​    assert(principal&gt;0);</p>
<p>​    return 100;</p>
<p>}</p>
<h3 id="什么时候使用断言？"><a href="#什么时候使用断言？" class="headerlink" title="什么时候使用断言？"></a>什么时候使用断言？</h3><p>断言不应该用于验证输入数据到一个public方法或命令行参数。IllegalArgumentException会是一个更好的选择。在public方法中，只用断言来检查它们根本不应该发生的情况。</p>
<h3 id="什么是初始化数据块？"><a href="#什么是初始化数据块？" class="headerlink" title="什么是初始化数据块？"></a>什么是初始化数据块？</h3><p>初始化数据块——当创建对象或加载类时运行的代码。</p>
<p>有两种类型的初始化数据块：</p>
<p>静态初始化器：加载类时运行的的代码</p>
<p>实例初始化器：创建新对象时运行的代码</p>
<h3 id="什么是静态初始化器？"><a href="#什么是静态初始化器？" class="headerlink" title="什么是静态初始化器？"></a>什么是静态初始化器？</h3><p>请看下面的例子：static{ 和 }之间的代码被称为静态初始化器。它只有在第一次加载类时运行。只有静态变量才可以在静态初始化器中进行访问。虽然创建了三个实例，但静态初始化器只运行一次。</p>
<p>/**</p>
<ul>
<li><p>Java学习交流QQ群：589809992 我们一起学Java！</p>
<p>*/</p>
</li>
</ul>
<p>public class InitializerExamples {</p>
<p>​    static int count;</p>
<p>​    int i;</p>
<p>​    static{</p>
<p>​        //This is a static initializers. Run only when Class is first loaded.</p>
<p>​        //Only static variables can be accessed</p>
<p>​        System.out.println(“Static Initializer”);</p>
<p>​        //i = 6;//COMPILER ERROR</p>
<p>​        System.out.println(“Count when Static Initializer is run is “ + count);</p>
<p>​    }</p>
<p>​    public static void main(String[] args) {</p>
<p>​        InitializerExamples example = new InitializerExamples();</p>
<p>​        InitializerExamples example2 = new InitializerExamples();</p>
<p>​        InitializerExamples example3 = new InitializerExamples();</p>
<p>​    }</p>
<p>}</p>
<p>示例输出</p>
<p>Static Initializer</p>
<p>Count when Static Initializer is run is 0.</p>
<h3 id="什么是实例初始化块？"><a href="#什么是实例初始化块？" class="headerlink" title="什么是实例初始化块？"></a>什么是实例初始化块？</h3><p>让我们来看一个例子：每次创建类的实例时，实例初始化器中的代码都会运行。</p>
<p>/**</p>
<ul>
<li><p>Java学习交流QQ群：589809992 我们一起学Java！</p>
<p>*/</p>
</li>
</ul>
<p>public class InitializerExamples {</p>
<p>​    static int count;</p>
<p>​    int i;</p>
<p>​    {</p>
<p>​        //This is an instance initializers. Run every time an object is created.</p>
<p>​        //static and instance variables can be accessed</p>
<p>​        System.out.println(“Instance Initializer”);</p>
<p>​        i = 6;</p>
<p>​        count = count + 1;</p>
<p>​        System.out.println(“Count when Instance Initializer is run is “ + count);</p>
<p>​    }</p>
<p>​    public static void main(String[] args) {</p>
<p>​        InitializerExamples example = new InitializerExamples();</p>
<p>​        InitializerExamples example1 = new InitializerExamples();</p>
<p>​        InitializerExamples example2 = new InitializerExamples();</p>
<p>​    }</p>
<p>}</p>
<p>示例输出</p>
<p>Instance Initializer</p>
<p>​      Count when Instance Initializer is run is 1</p>
<p>​      Instance Initializer</p>
<p>​      Count when Instance Initializer is run is 2</p>
<p>​      Instance Initializer</p>
<p>​      Count when Instance Initializer is run is 3</p>
<h3 id="什么是正则表达式？"><a href="#什么是正则表达式？" class="headerlink" title="什么是正则表达式？"></a>什么是正则表达式？</h3><p>正则表达式能让解析、扫描和分割字符串变得非常容易。Java中常用的正则表达式——Patter，Matcher和Scanner类。</p>
<h3 id="什么是令牌化？"><a href="#什么是令牌化？" class="headerlink" title="什么是令牌化？"></a>什么是令牌化？</h3><p>令牌化是指在分隔符的基础上将一个字符串分割为若干个子字符串。例如，分隔符；分割字符串ac;bd;def;e为四个子字符串ac，bd，def和e。</p>
<p>分隔符自身也可以是一个常见正则表达式。</p>
<p>String.split(regex)函数将regex作为参数。</p>
<h3 id="给出令牌化的例子？"><a href="#给出令牌化的例子？" class="headerlink" title="给出令牌化的例子？"></a>给出令牌化的例子？</h3><p>private static void tokenize(String string,String regex) {</p>
<p>​    String[] tokens = string.split(regex);</p>
<p>​    System.out.println(Arrays.toString(tokens));</p>
<p>}</p>
<p>tokenize(“ac;bd;def;e”,”;”);//[ac, bd, def, e]</p>
<h3 id="如何使用扫描器类（Scanner-Class）令牌化？"><a href="#如何使用扫描器类（Scanner-Class）令牌化？" class="headerlink" title="如何使用扫描器类（Scanner Class）令牌化？"></a>如何使用扫描器类（Scanner Class）令牌化？</h3><p>private static void tokenizeUsingScanner(String string,String regex) {</p>
<p>​    Scanner scanner = new Scanner(string);</p>
<p>​    scanner.useDelimiter(regex);</p>
<p>​    List<string> matches = new ArrayList<string>();</string></string></p>
<p>​    while(scanner.hasNext()){</p>
<p>​        matches.add(scanner.next());</p>
<p>​    }</p>
<p>​    System.out.println(matches);</p>
<p>}</p>
<p>tokenizeUsingScanner(“ac;bd;def;e”,”;”);//[ac, bd, def, e]</p>
<h3 id="如何添加小时-hour-到一个日期对象（Date-Objects）？"><a href="#如何添加小时-hour-到一个日期对象（Date-Objects）？" class="headerlink" title="如何添加小时(hour)到一个日期对象（Date Objects）？"></a>如何添加小时(hour)到一个日期对象（Date Objects）？</h3><p>现在，让我们如何看看添加小时到一个date对象。所有在date上的日期操作都需要通过添加毫秒到date才能完成。例如，如果我们想增加6个小时，那么我们需要将6小时换算成毫秒。6小时= 6  60  60 * 1000毫秒。请看以下的例子。</p>
<p>Date date = new Date();</p>
<p>//Increase time by 6 hrs</p>
<p>date.setTime(date.getTime() + 6 <em> 60 </em> 60 * 1000);</p>
<p>System.out.println(date);</p>
<p>//Decrease time by 6 hrs</p>
<p>date = new Date();</p>
<p>date.setTime(date.getTime() - 6 <em> 60 </em> 60 * 1000);</p>
<p>System.out.println(date);</p>
<h3 id="如何格式化日期对象？"><a href="#如何格式化日期对象？" class="headerlink" title="如何格式化日期对象？"></a>如何格式化日期对象？</h3><p>格式化日期需要使用DateFormat类完成。让我们看几个例子。</p>
<p>//Formatting Dates</p>
<p>System.out.println(DateFormat.getInstance().format(</p>
<p>​        date));//10/16/12 5:18 AM</p>
<p>带有区域设置的格式化日期如下所示：</p>
<p>System.out.println(DateFormat.getDateInstance(</p>
<p>​        DateFormat.FULL, new Locale(“it”, “IT”))</p>
<p>​        .format(date));//marted“ 16 ottobre 2012</p>
<p>System.out.println(DateFormat.getDateInstance(</p>
<p>​        DateFormat.FULL, Locale.ITALIAN)</p>
<p>​        .format(date));//marted“ 16 ottobre 2012</p>
<p>//This uses default locale US</p>
<p>System.out.println(DateFormat.getDateInstance(</p>
<p>​        DateFormat.FULL).format(date));//Tuesday, October 16, 2012</p>
<p>System.out.println(DateFormat.getDateInstance()</p>
<p>​        .format(date));//Oct 16, 2012</p>
<p>System.out.println(DateFormat.getDateInstance(</p>
<p>​        DateFormat.SHORT).format(date));//10/16/12</p>
<p>System.out.println(DateFormat.getDateInstance(</p>
<p>​        DateFormat.MEDIUM).format(date));//Oct 16, 2012</p>
<p>System.out.println(DateFormat.getDateInstance(</p>
<p>​        DateFormat.LONG).format(date));//October 16, 2012</p>
<h3 id="Java中日历类（Calendar-Class）的用途？"><a href="#Java中日历类（Calendar-Class）的用途？" class="headerlink" title="Java中日历类（Calendar Class）的用途？"></a>Java中日历类（Calendar Class）的用途？</h3><p>Calendar类在Java中用于处理日期。Calendar类提供了增加和减少天数、月数和年数的简便方法。它还提供了很多与日期有关的细节（这一年的哪一天？哪一周？等等）</p>
<h3 id="如何在Java中获取日历类（Calendar-Class）的实例？"><a href="#如何在Java中获取日历类（Calendar-Class）的实例？" class="headerlink" title="如何在Java中获取日历类（Calendar Class）的实例？"></a>如何在Java中获取日历类（Calendar Class）的实例？</h3><p>Calendar类不能通过使用new Calendar创建。得到Calendar类实例的最好办法是在Calendar中使用getInstance() static方法。</p>
<p>//Calendar calendar = new Calendar(); //COMPILER ERROR</p>
<p>Calendar calendar = Calendar.getInstance();</p>
<h3 id="解释一些日历类（Calendar-Class）中的重要方法？"><a href="#解释一些日历类（Calendar-Class）中的重要方法？" class="headerlink" title="解释一些日历类（Calendar Class）中的重要方法？"></a>解释一些日历类（Calendar Class）中的重要方法？</h3><p>在Calendar对象上设置日（day），月（month）或年（year）不难。对Day，Month或Year调用恰当Constant的set方法。下一个参数就是值。</p>
<p>calendar.set(Calendar.DATE, 24);</p>
<p>calendar.set(Calendar.MONTH, 8);//8 - September</p>
<p>calendar.set(Calendar.YEAR, 2010);</p>
<p>calendar get方法</p>
<p>要获取一个特定日期的信息——2010年9月24日。我们可以使用calendar get方法。已被传递的参数表示我们希望从calendar中获得的值—— 天或月或年或……你可以从calendar获取的值举例如下：</p>
<p>System.out.println(calendar.get(Calendar.YEAR));//2010</p>
<p>System.out.println(calendar.get(Calendar.MONTH));//8</p>
<p>System.out.println(calendar.get(Calendar.DATE));//24</p>
<p>System.out.println(calendar.get(Calendar.WEEK_OF_MONTH));//4</p>
<p>System.out.println(calendar.get(Calendar.WEEK_OF_YEAR));//39</p>
<p>System.out.println(calendar.get(Calendar.DAY_OF_YEAR));//267</p>
<p>System.out.println(calendar.getFirstDayOfWeek());//1 -&gt; Calendar.SUNDAY</p>
<h3 id="数字格式化类（Number-Format-Class）的用途？"><a href="#数字格式化类（Number-Format-Class）的用途？" class="headerlink" title="数字格式化类（Number Format Class）的用途？"></a>数字格式化类（Number Format Class）的用途？</h3><p>数字格式用于格式化数字到不同的区域和不同格式中。</p>
<p>使用默认语言环境的数字格式</p>
<p>System.out.println(NumberFormat.getInstance().format(321.24f));//321.24</p>
<p>使用区域设置的数字格式</p>
<p>使用荷兰语言环境格式化数字：</p>
<p>System.out.println(NumberFormat.getInstance(new Locale(“nl”)).format(4032.3f));//4.032,3</p>
<p>使用德国语言环境格式化数字：</p>
<p>System.out.println(NumberFormat.getInstance(Locale.GERMANY).format(4032.3f));//4.032,3</p>
<p>使用默认语言环境格式化货币</p>
<p>System.out.println(NumberFormat.getCurrencyInstance().format(40324.31f));//$40,324.31</p>
<p>使用区域设置格式化货币</p>
<p>使用荷兰语言环境格式化货币：</p>
<p>System.out.println(NumberFormat.getCurrencyInstance(new Locale(“nl”)).format(40324.31f));/</p>
<h3 id="后台从前端页面获取到表单数据的方法？请具体到细节，如Servlet如何接收？SpringMVC怎么接收或Structs2？"><a href="#后台从前端页面获取到表单数据的方法？请具体到细节，如Servlet如何接收？SpringMVC怎么接收或Structs2？" class="headerlink" title="后台从前端页面获取到表单数据的方法？请具体到细节，如Servlet如何接收？SpringMVC怎么接收或Structs2？"></a>后台从前端页面获取到表单数据的方法？请具体到细节，如Servlet如何接收？SpringMVC怎么接收或Structs2？</h3><h3 id="Spring-中-IOC-和-DI-的区别以及关系是什么、AOP是怎么实现的？"><a href="#Spring-中-IOC-和-DI-的区别以及关系是什么、AOP是怎么实现的？" class="headerlink" title="Spring 中 IOC 和 DI 的区别以及关系是什么、AOP是怎么实现的？"></a>Spring 中 IOC 和 DI 的区别以及关系是什么、AOP是怎么实现的？</h3>

    
    
    
	  <div class="full-width auto-padding tags">
      
        <a href="/tags/Java/">Java</a>
      
	  </div>
    
  </section>
</article>
    </div>
  
    <div class='post-wrapper'>
      <article class="post reveal">
  <section class="meta">
    
    <h2 class="title">
      <a href="/2018/10/20/Java-面试题系列篇-Struts-框架/">
        Java 面试题系列篇-struts 框架
      </a>
    </h2>
    
    <time>
      Oct 20, 2018
    </time>
		
  </section>
  <section class="article typo">
	  <h2 id="Struts-框架"><a href="#Struts-框架" class="headerlink" title="Struts 框架"></a>Struts 框架</h2><h3 id="Struts2-中action-是多实例还是单实例的？为什么？"><a href="#Struts2-中action-是多实例还是单实例的？为什么？" class="headerlink" title="Struts2 中action 是多实例还是单实例的？为什么？"></a>Struts2 中action 是多实例还是单实例的？为什么？</h3><h3 id="Struts2-中的拦截器如何配置？"><a href="#Struts2-中的拦截器如何配置？" class="headerlink" title="Struts2 中的拦截器如何配置？"></a>Struts2 中的拦截器如何配置？</h3><h3 id="SSH-框架或-SSM-框架整合思想是什么？关键-jar-包是哪几个？请具体阐述-jar-包的作用？"><a href="#SSH-框架或-SSM-框架整合思想是什么？关键-jar-包是哪几个？请具体阐述-jar-包的作用？" class="headerlink" title="SSH 框架或 SSM 框架整合思想是什么？关键 jar 包是哪几个？请具体阐述 jar 包的作用？"></a>SSH 框架或 SSM 框架整合思想是什么？关键 jar 包是哪几个？请具体阐述 jar 包的作用？</h3><h3 id="页面数据分页如何实现？"><a href="#页面数据分页如何实现？" class="headerlink" title="页面数据分页如何实现？"></a>页面数据分页如何实现？</h3>

    
    
    
	  <div class="full-width auto-padding tags">
      
        <a href="/tags/Java/">Java</a>
      
	  </div>
    
  </section>
</article>
    </div>
  
    <div class='post-wrapper'>
      <article class="post reveal">
  <section class="meta">
    
    <h2 class="title">
      <a href="/2018/10/20/Java-面试题系列篇-Spring-框架/">
        Java 面试题系列篇-Spring 框架
      </a>
    </h2>
    
    <time>
      Oct 20, 2018
    </time>
		
  </section>
  <section class="article typo">
	  <h2 id="Spring-框架"><a href="#Spring-框架" class="headerlink" title="Spring 框架"></a>Spring 框架</h2><h3 id="【Spring】使用Spring框架的好处是什么？"><a href="#【Spring】使用Spring框架的好处是什么？" class="headerlink" title="【Spring】使用Spring框架的好处是什么？"></a>【Spring】使用Spring框架的好处是什么？</h3><p>轻量：Spring 是轻量的，基本的版本大约2MB</p>
<p>控制反转：Spring通过控制反转实现了松散耦合，对象们给出它们的依赖，而不是创建或查找依赖的对象们</p>
<p>面向切面的编程(AOP)：Spring支持面向切面的编程，并且把应用业务逻辑和系统服务分开</p>
<p>容器：Spring 包含并管理应用中对象的生命周期和配置</p>
<p>MVC框架：Spring的WEB框架是个精心设计的框架，是Web框架的一个很好的替代品</p>
<p>事务管理：Spring 提供一个持续的事务管理接口，可以扩展到上至本地事务下至全局事务（JTA）</p>
<p>异常处理：Spring 提供方便的API把具体技术相关的异常（比如由JDBC，Hibernate or JDO抛出的）转化为一致的unchecked 异常</p>
<h3 id="什么是IoC和DI？DI是如何实现的？"><a href="#什么是IoC和DI？DI是如何实现的？" class="headerlink" title="什么是IoC和DI？DI是如何实现的？"></a>什么是IoC和DI？DI是如何实现的？</h3><p>答：IoC叫控制反转，是Inversion of Control的缩写，DI（Dependency Injection）叫依赖注入，是对IoC更简单的诠释。控制反转是把传统上由程序代码直接操控的对象的调用权交给容器，通过容器来实现对象组件的装配和管理。所谓的”控制反转”就是对组件对象控制权的转移，从程序代码本身转移到了外部容器，由容器来创建对象并管理对象之间的依赖关系。IoC体现了好莱坞原则 - “Don’t call me, we will call you”。依赖注入的基本原则是应用组件不应该负责查找资源或者其他依赖的协作对象。配置对象的工作应该由容器负责，查找资源的逻辑应该从应用组件的代码中抽取出来，交给容器来完成。DI是对IoC更准确的描述，即组件之间的依赖关系由容器在运行期决定，形象的来说，即由容器动态的将某种依赖关系注入到组件之中。</p>
<p>举个例子：一个类A需要用到接口B中的方法，那么就需要为类A和接口B建立关联或依赖关系，最原始的方法是在类A中创建一个接口B的实现类C的实例，但这种方法需要开发人员自行维护二者的依赖关系，也就是说当依赖关系发生变动的时候需要修改代码并重新构建整个系统。如果通过一个容器来管理这些对象以及对象的依赖关系，则只需要在类A中定义好用于关联接口B的方法（构造器或setter方法），将类A和接口B的实现类C放入容器中，通过对容器的配置来实现二者的关联。</p>
<p>依赖注入可以通过setter方法注入（设值注入）、构造器注入和接口注入三种方式来实现，Spring支持setter注入和构造器注入，通常使用构造器注入来注入必须的依赖关系，对于可选的依赖关系，则setter注入是更好的选择，setter注入需要类提供无参构造器或者无参的静态工厂方法来创建对象。</p>
<h3 id="Spring中Bean的作用域有哪些？"><a href="#Spring中Bean的作用域有哪些？" class="headerlink" title="Spring中Bean的作用域有哪些？"></a>Spring中Bean的作用域有哪些？</h3><p>答：在Spring的早期版本中，仅有两个作用域：singleton和prototype，前者表示Bean以单例的方式存在；后者表示每次从容器中调用Bean时，都会返回一个新的实例，prototype通常翻译为原型。</p>
<p>补充：设计模式中的创建型模式中也有一个原型模式，原型模式也是一个常用的模式，例如做一个室内设计软件，所有的素材都在工具箱中，而每次从工具箱中取出的都是素材对象的一个原型，可以通过对象克隆来实现原型模式。</p>
<p>Spring 2.x中针对WebApplicationContext新增了3个作用域，分别是：request（每次HTTP请求都会创建一个新的Bean）、session（同一个HttpSession共享同一个Bean，不同的HttpSession使用不同的Bean）和globalSession（同一个全局Session共享一个Bean）。</p>
<p>说明：单例模式和原型模式都是重要的设计模式。一般情况下，无状态或状态不可变的类适合使用单例模式。在传统开发中，由于DAO持有Connection这个非线程安全对象因而没有使用单例模式；但在Spring环境下，所有DAO类对可以采用单例模式，因为Spring利用AOP和Java API中的ThreadLocal对非线程安全的对象进行了特殊处理。</p>
<p>ThreadLocal为解决多线程程序的并发问题提供了一种新的思路。ThreadLocal，顾名思义是线程的一个本地化对象，当工作于多线程中的对象使用ThreadLocal维护变量时，ThreadLocal为每个使用该变量的线程分配一个独立的变量副本，所以每一个线程都可以独立的改变自己的副本，而不影响其他线程所对应的副本。从线程的角度看，这个变量就像是线程的本地变量。</p>
<p>ThreadLocal类非常简单好用，只有四个方法，能用上的也就是下面三个方法： </p>
<ul>
<li>void set(T value)：设置当前线程的线程局部变量的值。 </li>
<li>T get()：获得当前线程所对应的线程局部变量的值。 </li>
<li>void remove()：删除当前线程中线程局部变量的值。</li>
</ul>
<p>ThreadLocal是如何做到为每一个线程维护一份独立的变量副本的呢？在ThreadLocal类中有一个Map，键为线程对象，值是其线程对应的变量的副本，自己要模拟实现一个ThreadLocal类其实并不困难，代码如下所示：</p>
<p>import java.util.Collections;</p>
<p>import java.util.HashMap;</p>
<p>import java.util.Map;</p>
<p>public class MyThreadLocal<t> {</t></p>
<p>​    private Map&lt;Thread, T&gt; map = Collections.synchronizedMap(new HashMap&lt;Thread, T&gt;());</p>
<p>​    public void set(T newValue) {</p>
<p>​        map.put(Thread.currentThread(), newValue);</p>
<p>​    }</p>
<p>​    public T get() {</p>
<p>​        return map.get(Thread.currentThread());</p>
<p>​    }</p>
<p>​    public void remove() {</p>
<p>​        map.remove(Thread.currentThread());</p>
<p>​    }</p>
<p>}</p>
<h3 id="解释一下什么叫AOP（面向切面编程）？"><a href="#解释一下什么叫AOP（面向切面编程）？" class="headerlink" title="解释一下什么叫AOP（面向切面编程）？"></a>解释一下什么叫AOP（面向切面编程）？</h3><p>答：AOP（Aspect-Oriented Programming）指一种程序设计范型，该范型以一种称为切面（aspect）的语言构造为基础，切面是一种新的模块化机制，用来描述分散在对象、类或方法中的横切关注点（crosscutting concern）。</p>
<h3 id="你是如何理解”横切关注”这个概念的？"><a href="#你是如何理解”横切关注”这个概念的？" class="headerlink" title="你是如何理解”横切关注”这个概念的？"></a>你是如何理解”横切关注”这个概念的？</h3><p>答：”横切关注”是会影响到整个应用程序的关注功能，它跟正常的业务逻辑是正交的，没有必然的联系，但是几乎所有的业务逻辑都会涉及到这些关注功能。通常，事务、日志、安全性等关注就是应用中的横切关注功能。</p>
<h3 id="你如何理解AOP中的连接点（Joinpoint）、切点（Pointcut）、增强（Advice）、引介（Introduction）、织入（Weaving）、切面（Aspect）这些概念？"><a href="#你如何理解AOP中的连接点（Joinpoint）、切点（Pointcut）、增强（Advice）、引介（Introduction）、织入（Weaving）、切面（Aspect）这些概念？" class="headerlink" title="你如何理解AOP中的连接点（Joinpoint）、切点（Pointcut）、增强（Advice）、引介（Introduction）、织入（Weaving）、切面（Aspect）这些概念？"></a>你如何理解AOP中的连接点（Joinpoint）、切点（Pointcut）、增强（Advice）、引介（Introduction）、织入（Weaving）、切面（Aspect）这些概念？</h3><p>答：<br>a. 连接点（Joinpoint）：程序执行的某个特定位置（如：某个方法调用前、调用后，方法抛出异常后）。一个类或一段程序代码拥有一些具有边界性质的特定点，这些代码中的特定点就是连接点。Spring仅支持方法的连接点。<br>b. 切点（Pointcut）：如果连接点相当于数据中的记录，那么切点相当于查询条件，一个切点可以匹配多个连接点。Spring AOP的规则解析引擎负责解析切点所设定的查询条件，找到对应的连接点。<br>c. 增强（Advice）：增强是织入到目标类连接点上的一段程序代码。Spring提供的增强接口都是带方位名的，如：BeforeAdvice、AfterReturningAdvice、ThrowsAdvice等。很多资料上将增强译为“通知”，这明显是个词不达意的翻译，让很多程序员困惑了许久。</p>
<p>说明： Advice在国内的很多书面资料中都被翻译成”通知”，但是很显然这个翻译无法表达其本质，有少量的读物上将这个词翻译为”增强”，这个翻译是对Advice较为准确的诠释，我们通过AOP将横切关注功能加到原有的业务逻辑上，这就是对原有业务逻辑的一种增强，这种增强可以是前置增强、后置增强、返回后增强、抛异常时增强和包围型增强。</p>
<p>d. 引介（Introduction）：引介是一种特殊的增强，它为类添加一些属性和方法。这样，即使一个业务类原本没有实现某个接口，通过引介功能，可以动态的未该业务类添加接口的实现逻辑，让业务类成为这个接口的实现类。<br>e. 织入（Weaving）：织入是将增强添加到目标类具体连接点上的过程，AOP有三种织入方式：①编译期织入：需要特殊的Java编译期（例如AspectJ的ajc）；②装载期织入：要求使用特殊的类加载器，在装载类的时候对类进行增强；③运行时织入：在运行时为目标类生成代理实现增强。Spring采用了动态代理的方式实现了运行时织入，而AspectJ采用了编译期织入和装载期织入的方式。<br>f. 切面（Aspect）：切面是由切点和增强（引介）组成的，它包括了对横切关注功能的定义，也包括了对连接点的定义。</p>
<p>补充：代理模式是GoF提出的23种设计模式中最为经典的模式之一，代理模式是对象的结构模式，它给某一个对象提供一个代理对象，并由代理对象控制对原对象的引用。简单的说，代理对象可以完成比原对象更多的职责，当需要为原对象添加横切关注功能时，就可以使用原对象的代理对象。我们在打开Office系列的Word文档时，如果文档中有插图，当文档刚加载时，文档中的插图都只是一个虚框占位符，等用户真正翻到某页要查看该图片时，才会真正加载这张图，这其实就是对代理模式的使用，代替真正图片的虚框就是一个虚拟代理；Hibernate的load方法也是返回一个虚拟代理对象，等用户真正需要访问对象的属性时，才向数据库发出SQL语句获得真实对象。</p>
<p>下面用一个找枪手代考的例子演示代理模式的使用：</p>
<p>/**</p>
<ul>
<li>参考人员接口</li>
<li><p>@author 骆昊</p>
<p>*</p>
<p>*/</p>
</li>
</ul>
<p>public interface Candidate {</p>
<p>​    /**</p>
<p>​     * 答题</p>
<p>​     */</p>
<p>​    public void answerTheQuestions();</p>
<p>}</p>
<p>/**</p>
<ul>
<li>懒学生</li>
<li><p>@author 骆昊</p>
<p>*</p>
<p>*/</p>
</li>
</ul>
<p>public class LazyStudent implements Candidate {</p>
<p>​    private String name;        // 姓名</p>
<p>​    public LazyStudent(String name) {</p>
<p>​        this.name = name;</p>
<p>​    }</p>
<p>​    @Override</p>
<p>​    public void answerTheQuestions() {</p>
<p>​        // 懒学生只能写出自己的名字不会答题</p>
<p>​        System.out.println(“姓名: “ + name);</p>
<p>​    }</p>
<p>}</p>
<p>/**</p>
<ul>
<li>枪手</li>
<li><p>@author 骆昊</p>
<p>*</p>
<p>*/</p>
</li>
</ul>
<p>public class Gunman implements Candidate {</p>
<p>​    private Candidate target;   // 被代理对象</p>
<p>​    public Gunman(Candidate target) {</p>
<p>​        this.target = target;</p>
<p>​    }</p>
<p>​    @Override</p>
<p>​    public void answerTheQuestions() {</p>
<p>​        // 枪手要写上代考的学生的姓名</p>
<p>​        target.answerTheQuestions();</p>
<p>​        // 枪手要帮助懒学生答题并交卷</p>
<p>​        System.out.println(“奋笔疾书正确答案”);</p>
<p>​        System.out.println(“交卷”);</p>
<p>​    }</p>
<p>}</p>
<p>public class ProxyTest1 {</p>
<p>​    public static void main(String[] args) {</p>
<p>​        Candidate c = new Gunman(new LazyStudent(“王小二”));</p>
<p>​        c.answerTheQuestions();</p>
<p>​    }</p>
<p>}</p>
<p>说明：从JDK 1.3开始，Java提供了动态代理技术，允许开发者在运行时创建接口的代理实例，主要包括Proxy类和InvocationHandler接口。下面的例子使用动态代理为ArrayList编写一个代理，在添加和删除元素时，在控制台打印添加或删除的元素以及ArrayList的大小：</p>
<p>import java.lang.reflect.InvocationHandler;</p>
<p>import java.lang.reflect.Method;</p>
<p>import java.util.List;</p>
<p>public class ListProxy<t> implements InvocationHandler {</t></p>
<p>​    private List<t> target;</t></p>
<p>​    public ListProxy(List<t> target) {</t></p>
<p>​        this.target = target;</p>
<p>​    }</p>
<p>​    @Override</p>
<p>​    public Object invoke(Object proxy, Method method, Object[] args)</p>
<p>​            throws Throwable {</p>
<p>​        Object retVal = null;</p>
<p>​        System.out.println(“[“ + method.getName() + “: “ + args[0] + “]”);</p>
<p>​        retVal = method.invoke(target, args);</p>
<p>​        System.out.println(“[size=” + target.size() + “]”);</p>
<p>​        return retVal;</p>
<p>​    }</p>
<p>}</p>
<p>import java.lang.reflect.Proxy;</p>
<p>import java.util.ArrayList;</p>
<p>import java.util.List;</p>
<p>public class ProxyTest2 {</p>
<p>​    @SuppressWarnings(“unchecked”)</p>
<p>​    public static void main(String[] args) {</p>
<p>​        List<string> list = new ArrayList<string>();</string></string></p>
<p>​        Class&lt;?&gt; clazz = list.getClass();</p>
<p>​        ListProxy<string> myProxy = new ListProxy<string>(list);</string></string></p>
<p>​        List<string> newList = (List<string>) </string></string></p>
<p>​                Proxy.newProxyInstance(clazz.getClassLoader(), </p>
<p>​                clazz.getInterfaces(), myProxy);</p>
<p>​        newList.add(“apple”);</p>
<p>​        newList.add(“banana”);</p>
<p>​        newList.add(“orange”);</p>
<p>​        newList.remove(“banana”);</p>
<p>​    }</p>
<p>}</p>
<p>说明：使用Java的动态代理有一个局限性就是代理的类必须要实现接口，虽然面向接口编程是每个优秀的Java程序都知道的规则，但现实往往不尽如人意，对于没有实现接口的类如何为其生成代理呢？继承！继承是最经典的扩展已有代码能力的手段，虽然继承常常被初学者滥用，但继承也常常被进阶的程序员忽视。CGLib采用非常底层的字节码生成技术，通过为一个类创建子类来生成代理，它弥补了Java动态代理的不足，因此Spring中动态代理和CGLib都是创建代理的重要手段，对于实现了接口的类就用动态代理为其生成代理类，而没有实现接口的类就用CGLib通过继承的方式为其创建代理。</p>
<h3 id="Spring中自动装配的方式有哪些？"><a href="#Spring中自动装配的方式有哪些？" class="headerlink" title="Spring中自动装配的方式有哪些？"></a>Spring中自动装配的方式有哪些？</h3><p> 答： </p>
<ul>
<li>no：不进行自动装配，手动设置Bean的依赖关系。 </li>
<li>byName：根据Bean的名字进行自动装配。 </li>
<li>byType：根据Bean的类型进行自动装配。 </li>
<li>constructor：类似于byType，不过是应用于构造器的参数，如果正好有一个Bean与构造器的参数类型相同则可以自动装配，否则会导致错误。 </li>
<li>autodetect：如果有默认的构造器，则通过constructor的方式进行自动装配，否则使用byType的方式进行自动装配。</li>
</ul>
<p>说明：自动装配没有自定义装配方式那么精确，而且不能自动装配简单属性（基本类型、字符串等），在使用时应注意。</p>
<h3 id="Spring中如何使用注解来配置Bean？有哪些相关的注解？"><a href="#Spring中如何使用注解来配置Bean？有哪些相关的注解？" class="headerlink" title="Spring中如何使用注解来配置Bean？有哪些相关的注解？"></a>Spring中如何使用注解来配置Bean？有哪些相关的注解？</h3><p>答：首先需要在Spring配置文件中增加如下配置：</p>
<p>&lt;context:component-scan base-package=”org.example”/&gt;</p>
<p>然后可以用@Component、@Controller、@Service、@Repository注解来标注需要由Spring IoC容器进行对象托管的类。这几个注解没有本质区别，只不过@Controller通常用于控制器，@Service通常用于业务逻辑类，@Repository通常用于仓储类（例如我们的DAO实现类），普通的类用@Component来标注。</p>
<h3 id="Spring支持的事务管理类型有哪些？你在项目中使用哪种方式？"><a href="#Spring支持的事务管理类型有哪些？你在项目中使用哪种方式？" class="headerlink" title="Spring支持的事务管理类型有哪些？你在项目中使用哪种方式？"></a>Spring支持的事务管理类型有哪些？你在项目中使用哪种方式？</h3><p>答：Spring支持编程式事务管理和声明式事务管理。许多Spring框架的用户选择声明式事务管理，因为这种方式和应用程序的关联较少，因此更加符合轻量级容器的概念。声明式事务管理要优于编程式事务管理，尽管在灵活性方面它弱于编程式事务管理，因为编程式事务允许你通过代码控制业务。</p>
<p>事务分为全局事务和局部事务。全局事务由应用服务器管理，需要底层服务器JTA支持（如WebLogic、WildFly等）。局部事务和底层采用的持久化方案有关，例如使用JDBC进行持久化时，需要使用Connetion对象来操作事务；而采用Hibernate进行持久化时，需要使用Session对象来操作事务。</p>
<p>Spring提供了如下所示的事务管理器。</p>
<table>
<thead>
<tr>
<th>事务管理器实现类</th>
<th>目标对象</th>
</tr>
</thead>
<tbody>
<tr>
<td>DataSourceTransactionManager</td>
<td>注入DataSource</td>
</tr>
<tr>
<td>HibernateTransactionManager</td>
<td>注入SessionFactory</td>
</tr>
<tr>
<td>JdoTransactionManager</td>
<td>管理JDO事务</td>
</tr>
<tr>
<td>JtaTransactionManager</td>
<td>使用JTA管理事务</td>
</tr>
<tr>
<td>PersistenceBrokerTransactionManager</td>
<td>管理Apache的OJB事务</td>
</tr>
</tbody>
</table>
<p>这些事务的父接口都是PlatformTransactionManager。Spring的事务管理机制是一种典型的策略模式，PlatformTransactionManager代表事务管理接口，该接口定义了三个方法，该接口并不知道底层如何管理事务，但是它的实现类必须提供getTransaction()方法（开启事务）、commit()方法（提交事务）、rollback()方法（回滚事务）的多态实现，这样就可以用不同的实现类代表不同的事务管理策略。使用JTA全局事务策略时，需要底层应用服务器支持，而不同的应用服务器所提供的JTA全局事务可能存在细节上的差异，因此实际配置全局事务管理器是可能需要使用JtaTransactionManager的子类，如：WebLogicJtaTransactionManager（Oracle的WebLogic服务器提供）、UowJtaTransactionManager（IBM的WebSphere服务器提供）等。</p>
<p>编程式事务管理如下所示。</p>
<p>&lt;?xml version=”1.0” encoding=”UTF-8”?&gt;</p>
 <beans xmlns="http://www.springframework.org/schema/beans" ​ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd

​     http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"><br><br><br><br>​     &lt;context:component-scan base-package=”com.jackfrued”/&gt;<br><br><br><br>​     <bean id="propertyConfig" ​ class="org.springframework.beans.factory.config.

  PropertyPlaceholderConfigurer"><br><br>​         <property name="location"><br><br>​             <value>jdbc.properties</value><br><br>​         </property><br><br>​     </bean><br><br><br><br>​     <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"><br><br>​         <property name="driverClassName"><br><br>​             <value>${db.driver}</value><br><br>​         </property><br><br>​         <property name="url"><br><br>​             <value>${db.url}</value><br><br>​         </property><br><br>​         <property name="username"><br><br>​             <value>${db.username}</value><br><br>​         </property><br><br>​         <property name="password"><br><br>​             <value>${db.password}</value><br><br>​         </property><br><br>​     </bean><br><br><br><br>​     <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><br><br>​         <property name="dataSource"><br><br>​             <ref bean="dataSource"><br><br>​         </ref></property><br><br>​     </bean><br><br><br><br>​     <!-- JDBC事务管理器 --><br><br>​     <bean id="transactionManager" ​ class="org.springframework.jdbc.datasource.

​       DataSourceTransactionManager" 　scope="singleton"><br><br>​         <property name="dataSource"><br><br>​             <ref bean="dataSource"><br><br>​         </ref></property><br><br>​     </bean><br><br><br><br>​     <!-- 声明事务模板 --><br><br>​     <bean id="transactionTemplate" ​ class="org.springframework.transaction.support.

   TransactionTemplate"><br><br>​         <property name="transactionManager"><br><br>​             <ref bean="transactionManager"><br><br>​         </ref></property><br><br>​     </bean><br><br><br><br></beans>

<p>package com.jackfrued.dao.impl;</p>
<p>import org.springframework.beans.factory.annotation.Autowired;</p>
<p>import org.springframework.jdbc.core.JdbcTemplate;</p>
<p>import com.jackfrued.dao.EmpDao;</p>
<p>import com.jackfrued.entity.Emp;</p>
<p>@Repository</p>
<p>public class EmpDaoImpl implements EmpDao {</p>
<p>​    @Autowired</p>
<p>​    private JdbcTemplate jdbcTemplate;</p>
<p>​    @Override</p>
<p>​    public boolean save(Emp emp) {</p>
<p>​        String sql = “insert into emp values (?,?,?)”;</p>
<p>​        return jdbcTemplate.update(sql, emp.getId(), emp.getName(), emp.getBirthday()) == 1;</p>
<p>​    }</p>
<p>}</p>
<p>package com.jackfrued.biz.impl;</p>
<p>import org.springframework.beans.factory.annotation.Autowired;</p>
<p>import org.springframework.stereotype.Service;</p>
<p>import org.springframework.transaction.TransactionStatus;</p>
<p>import org.springframework.transaction.support.TransactionCallbackWithoutResult;</p>
<p>import org.springframework.transaction.support.TransactionTemplate;</p>
<p>import com.jackfrued.biz.EmpService;</p>
<p>import com.jackfrued.dao.EmpDao;</p>
<p>import com.jackfrued.entity.Emp;</p>
<p>@Service</p>
<p>public class EmpServiceImpl implements EmpService {</p>
<p>​    @Autowired</p>
<p>​    private TransactionTemplate txTemplate;</p>
<p>​    @Autowired</p>
<p>​    private EmpDao empDao;</p>
<p>​    @Override</p>
<p>​    public void addEmp(final Emp emp) {</p>
<p>​        txTemplate.execute(new TransactionCallbackWithoutResult() {</p>
<p>​            @Override</p>
<p>​            protected void doInTransactionWithoutResult(TransactionStatus txStatus) {</p>
<p>​                empDao.save(emp);</p>
<p>​            }</p>
<p>​        });</p>
<p>​    }</p>
<p>}</p>
<p>声明式事务如下图所示，以Spring整合Hibernate 3为例，包括完整的DAO和业务逻辑代码。</p>
<p>&lt;?xml version=”1.0” encoding=”UTF-8”?&gt;</p>
<beans xmlns="http://www.springframework.org/schema/beans" ​ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemalocation="http://www.springframework.org/schema/beans

​           http://www.springframework.org/schema/beans/spring-beans-3.2.xsd

​           http://www.springframework.org/schema/context

​           http://www.springframework.org/schema/context/spring-context-3.2.xsd

​           http://www.springframework.org/schema/aop

​           http://www.springframework.org/schema/aop/spring-aop-3.2.xsd

​           http://www.springframework.org/schema/tx

​           http://www.springframework.org/schema/tx/spring-tx-3.2.xsd"><br><br><br><br>​    <!-- 配置由Spring IoC容器托管的对象对应的被注解的类所在的包 --><br><br>​    &lt;context:component-scan base-package=”com.jackfrued” /&gt;<br><br><br><br>​    <!-- 配置通过自动生成代理实现AOP功能 --><br><br>​    &lt;aop:aspectj-autoproxy /&gt;<br><br><br><br>​    <!-- 配置数据库连接池 (DBCP) --><br><br>​    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" ​ destroy-method="close"><br><br>​        <!-- 配置驱动程序类 --><br><br>​        <property name="driverClassName" value="com.mysql.jdbc.Driver"><br><br>​        <!-- 配置连接数据库的URL --><br><br>​        <property name="url" value="jdbc:mysql://localhost:3306/myweb"><br><br>​        <!-- 配置访问数据库的用户名 --><br><br>​        <property name="username" value="root"><br><br>​        <!-- 配置访问数据库的口令 --><br><br>​        <property name="password" value="123456"><br><br>​        <!-- 配置最大连接数 --><br><br>​        <property name="maxActive" value="150"><br><br>​        <!-- 配置最小空闲连接数 --><br><br>​        <property name="minIdle" value="5"><br><br>​        <!-- 配置最大空闲连接数 --><br><br>​        <property name="maxIdle" value="20"><br><br>​        <!-- 配置初始连接数 --><br><br>​        <property name="initialSize" value="10"><br><br>​        <!-- 配置连接被泄露时是否生成日志 --><br><br>​        <property name="logAbandoned" value="true"><br><br>​        <!-- 配置是否删除超时连接 --><br><br>​        <property name="removeAbandoned" value="true"><br><br>​        <!-- 配置删除超时连接的超时门限值(以秒为单位) --><br><br>​        <property name="removeAbandonedTimeout" value="120"><br><br>​        <!-- 配置超时等待时间(以毫秒为单位) --><br><br>​        <property name="maxWait" value="5000"><br><br>​        <!-- 配置空闲连接回收器线程运行的时间间隔(以毫秒为单位) --><br><br>​        <property name="timeBetweenEvictionRunsMillis" value="300000"><br><br>​        <!-- 配置连接空闲多长时间后(以毫秒为单位)被断开连接 --><br><br>​        <property name="minEvictableIdleTimeMillis" value="60000"><br><br>​    </property></property></property></property></property></property></property></property></property></property></property></property></property></property></bean><br><br><br><br>​    <!-- 配置Spring提供的支持注解ORM映射的Hibernate会话工厂 --><br><br>​    <bean id="sessionFactory" ​ class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean"><br><br>​        <!-- 通过setter注入数据源属性 --><br><br>​        <property name="dataSource" ref="dataSource"><br><br>​        <!-- 配置实体类所在的包 --><br><br>​        <property name="packagesToScan" value="com.jackfrued.entity"><br><br>​        <!-- 配置Hibernate的相关属性 --><br><br>​        <property name="hibernateProperties"><br><br>​            <!-- 在项目调试完成后要删除show_sql和format_sql属性否则对性能有显著影响 --><br><br>​            <value><br><br>​                hibernate.dialect=org.hibernate.dialect.MySQL5Dialect<br><br>​            </value><br><br>​        </property><br><br>​    </property></property></bean><br><br><br><br>​    <!-- 配置Spring提供的Hibernate事务管理器 --><br><br>​    <bean id="transactionManager" ​ class="org.springframework.orm.hibernate3.HibernateTransactionManager"><br><br>​        <!-- 通过setter注入Hibernate会话工厂 --><br><br>​        <property name="sessionFactory" ref="sessionFactory"><br><br>​    </property></bean><br><br><br><br>​    <!-- 配置基于注解配置声明式事务 --><br><br>​    &lt;tx:annotation-driven /&gt;<br><br><br><br></beans>

<p>package com.jackfrued.dao;</p>
<p>import java.io.Serializable;</p>
<p>import java.util.List;</p>
<p>import com.jackfrued.comm.QueryBean;</p>
<p>import com.jackfrued.comm.QueryResult;</p>
<p>/**</p>
<ul>
<li>数据访问对象接口(以对象为单位封装CRUD操作)</li>
<li><p>@author 骆昊</p>
<p>*</p>
</li>
<li><p>@param <e> 实体类型</e></p>
</li>
<li><p>@param <k> 实体标识字段的类型</k></p>
<p>*/</p>
</li>
</ul>
<p>public interface BaseDao &lt;E, K extends Serializable&gt; {</p>
<p>​    /**</p>
<p>​     * 新增</p>
<p>​     * @param entity 业务实体对象</p>
<p>​     * @return 增加成功返回实体对象的标识</p>
<p>​     */</p>
<p>​    public K save(E entity);</p>
<p>​    /**</p>
<p>​     * 删除</p>
<p>​     * @param entity 业务实体对象</p>
<p>​     */</p>
<p>​    public void delete(E entity);</p>
<p>​    /**</p>
<p>​     * 根据ID删除</p>
<p>​     * @param id 业务实体对象的标识</p>
<p>​     * @return 删除成功返回true否则返回false</p>
<p>​     */</p>
<p>​    public boolean deleteById(K id);</p>
<p>​    /**</p>
<p>​     * 修改</p>
<p>​     * @param entity 业务实体对象</p>
<p>​     * @return 修改成功返回true否则返回false</p>
<p>​     */</p>
<p>​    public void update(E entity);</p>
<p>​    /**</p>
<p>​     * 根据ID查找业务实体对象</p>
<p>​     * @param id 业务实体对象的标识</p>
<p>​     * @return 业务实体对象对象或null</p>
<p>​     */</p>
<p>​    public E findById(K id);</p>
<p>​    /**</p>
<p>​     * 根据ID查找业务实体对象</p>
<p>​     * @param id 业务实体对象的标识</p>
<p>​     * @param lazy 是否使用延迟加载</p>
<p>​     * @return 业务实体对象对象</p>
<p>​     */</p>
<p>​    public E findById(K id, boolean lazy);</p>
<p>​    /**</p>
<p>​     * 查找所有业务实体对象</p>
<p>​     * @return 装所有业务实体对象的列表容器</p>
<p>​     */</p>
<p>​    public List<e> findAll();</e></p>
<p>​    /**</p>
<p>​     * 分页查找业务实体对象</p>
<p>​     * @param page 页码</p>
<p>​     * @param size 页面大小</p>
<p>​     * @return 查询结果对象</p>
<p>​     */</p>
<p>​    public QueryResult<e> findByPage(int page, int size);</e></p>
<p>​    /**</p>
<p>​     * 分页查找业务实体对象</p>
<p>​     * @param queryBean 查询条件对象</p>
<p>​     * @param page 页码</p>
<p>​     * @param size 页面大小</p>
<p>​     * @return 查询结果对象</p>
<p>​     */</p>
<p>​    public QueryResult<e> findByPage(QueryBean queryBean, int page, int size);</e></p>
<p>}</p>
<p>package com.jackfrued.dao;</p>
<p>import java.io.Serializable;</p>
<p>import java.util.List;</p>
<p>import com.jackfrued.comm.QueryBean;</p>
<p>import com.jackfrued.comm.QueryResult;</p>
<p>/**</p>
<ul>
<li>BaseDao的缺省适配器</li>
<li><p>@author 骆昊</p>
<p>*</p>
</li>
<li><p>@param <e> 实体类型</e></p>
</li>
<li><p>@param <k> 实体标识字段的类型</k></p>
<p>*/</p>
</li>
</ul>
<p>public abstract class BaseDaoAdapter&lt;E, K extends Serializable&gt; implements</p>
<p>​        BaseDao&lt;E, K&gt; {</p>
<p>​    @Override</p>
<p>​    public K save(E entity) {</p>
<p>​        return null;</p>
<p>​    }</p>
<p>​    @Override</p>
<p>​    public void delete(E entity) {</p>
<p>​    }</p>
<p>​    @Override</p>
<p>​    public boolean deleteById(K id) {</p>
<p>​        E entity = findById(id);</p>
<p>​        if(entity != null) {</p>
<p>​            delete(entity);</p>
<p>​            return true;</p>
<p>​        }</p>
<p>​        return false;</p>
<p>​    }</p>
<p>​    @Override</p>
<p>​    public void update(E entity) {</p>
<p>​    }</p>
<p>​    @Override</p>
<p>​    public E findById(K id) {</p>
<p>​        return null;</p>
<p>​    }</p>
<p>​    @Override</p>
<p>​    public E findById(K id, boolean lazy) {</p>
<p>​        return null;</p>
<p>​    }</p>
<p>​    @Override</p>
<p>​    public List<e> findAll() {</e></p>
<p>​        return null;</p>
<p>​    }</p>
<p>​    @Override</p>
<p>​    public QueryResult<e> findByPage(int page, int size) {</e></p>
<p>​        return null;</p>
<p>​    }</p>
<p>​    @Override</p>
<p>​    public QueryResult<e> findByPage(QueryBean queryBean, int page, int size) {</e></p>
<p>​        return null;</p>
<p>​    }</p>
<p>}</p>
<p>package com.jackfrued.dao;</p>
<p>import java.io.Serializable;</p>
<p>import java.lang.reflect.ParameterizedType;</p>
<p>import java.util.ArrayList;</p>
<p>import java.util.Collections;</p>
<p>import java.util.List;</p>
<p>import org.hibernate.Query;</p>
<p>import org.hibernate.Session;</p>
<p>import org.hibernate.SessionFactory;</p>
<p>import org.springframework.beans.factory.annotation.Autowired;</p>
<p>import com.jackfrued.comm.HQLQueryBean;</p>
<p>import com.jackfrued.comm.QueryBean;</p>
<p>import com.jackfrued.comm.QueryResult;</p>
<p>/**</p>
<ul>
<li>基于Hibernate的BaseDao实现类</li>
<li><p>@author 骆昊</p>
<p>*</p>
</li>
<li><p>@param <e> 实体类型</e></p>
</li>
<li><p>@param <k> 主键类型</k></p>
<p>*/</p>
</li>
</ul>
<p>@SuppressWarnings(value = {“unchecked”})</p>
<p>public abstract class BaseDaoHibernateImpl&lt;E, K extends Serializable&gt; extends BaseDaoAdapter&lt;E, K&gt; {</p>
<p>​    @Autowired</p>
<p>​    protected SessionFactory sessionFactory;</p>
<p>​    private Class&lt;?&gt; entityClass;       // 业务实体的类对象</p>
<p>​    private String entityName;          // 业务实体的名字</p>
<p>​    public BaseDaoHibernateImpl() {</p>
<p>​        ParameterizedType pt = (ParameterizedType) this.getClass().getGenericSuperclass();</p>
<p>​        entityClass = (Class&lt;?&gt;) pt.getActualTypeArguments()[0];</p>
<p>​        entityName = entityClass.getSimpleName();</p>
<p>​    }</p>
<p>​    @Override</p>
<p>​    public K save(E entity) {</p>
<p>​        return (K) sessionFactory.getCurrentSession().save(entity);</p>
<p>​    }</p>
<p>​    @Override</p>
<p>​    public void delete(E entity) {</p>
<p>​        sessionFactory.getCurrentSession().delete(entity);</p>
<p>​    }</p>
<p>​    @Override</p>
<p>​    public void update(E entity) {</p>
<p>​        sessionFactory.getCurrentSession().update(entity);</p>
<p>​    }</p>
<p>​    @Override</p>
<p>​    public E findById(K id) {</p>
<p>​        return findById(id, false);</p>
<p>​    }</p>
<p>​    @Override</p>
<p>​    public E findById(K id, boolean lazy) {</p>
<p>​        Session session = sessionFactory.getCurrentSession();</p>
<p>​        return (E) (lazy? session.load(entityClass, id) : session.get(entityClass, id));</p>
<p>​    }</p>
<p>​    @Override</p>
<p>​    public List<e> findAll() {</e></p>
<p>​        return sessionFactory.getCurrentSession().createCriteria(entityClass).list();</p>
<p>​    }</p>
<p>​    @Override</p>
<p>​    public QueryResult<e> findByPage(int page, int size) {</e></p>
<p>​        return new QueryResult<e>(</e></p>
<p>​            findByHQLAndPage(“from “ + entityName , page, size),</p>
<p>​            getCountByHQL(“select count(*) from “ + entityName)</p>
<p>​        );</p>
<p>​    }</p>
<p>​    @Override</p>
<p>​    public QueryResult<e> findByPage(QueryBean queryBean, int page, int size) {</e></p>
<p>​        if(queryBean instanceof HQLQueryBean) {</p>
<p>​            HQLQueryBean hqlQueryBean = (HQLQueryBean) queryBean;</p>
<p>​            return new QueryResult<e>(</e></p>
<p>​                findByHQLAndPage(hqlQueryBean.getQueryString(), page, size, hqlQueryBean.getParameters()),</p>
<p>​                getCountByHQL(hqlQueryBean.getCountString(), hqlQueryBean.getParameters())</p>
<p>​            );</p>
<p>​        }</p>
<p>​        return null;</p>
<p>​    }</p>
<p>​    /**</p>
<p>​     * 根据HQL和可变参数列表进行查询</p>
<p>​     * @param hql 基于HQL的查询语句</p>
<p>​     * @param params 可变参数列表</p>
<p>​     * @return 持有查询结果的列表容器或空列表容器</p>
<p>​     */</p>
<p>​    protected List<e> findByHQL(String hql, Object… params) {</e></p>
<p>​        return this.findByHQL(hql, getParamList(params));</p>
<p>​    }</p>
<p>​    /**</p>
<p>​     * 根据HQL和参数列表进行查询</p>
<p>​     * @param hql 基于HQL的查询语句</p>
<p>​     * @param params 查询参数列表</p>
<p>​     * @return 持有查询结果的列表容器或空列表容器</p>
<p>​     */</p>
<p>​    protected List<e> findByHQL(String hql, List<object> params) {</object></e></p>
<p>​        List<e> list = createQuery(hql, params).list();</e></p>
<p>​        return list != null &amp;&amp; list.size() &gt; 0 ? list : Collections.EMPTY_LIST;</p>
<p>​    }</p>
<p>​    /**</p>
<p>​     * 根据HQL和参数列表进行分页查询</p>
<p>​     * @param hql 基于HQL的查询语句</p>
<p>​     * @page 页码</p>
<p>​     * @size 页面大小</p>
<p>​     * @param params 可变参数列表</p>
<p>​     * @return 持有查询结果的列表容器或空列表容器</p>
<p>​     */</p>
<p>​    protected List<e> findByHQLAndPage(String hql, int page, int size, Object… params) {</e></p>
<p>​        return this.findByHQLAndPage(hql, page, size, getParamList(params));</p>
<p>​    }</p>
<p>​    /**</p>
<p>​     * 根据HQL和参数列表进行分页查询</p>
<p>​     * @param hql 基于HQL的查询语句</p>
<p>​     * @page 页码</p>
<p>​     * @size 页面大小</p>
<p>​     * @param params 查询参数列表</p>
<p>​     * @return 持有查询结果的列表容器或空列表容器</p>
<p>​     */</p>
<p>​    protected List<e> findByHQLAndPage(String hql, int page, int size, List<object> params) {</object></e></p>
<p>​        List<e> list = createQuery(hql, params)</e></p>
<p>​                .setFirstResult((page - 1) * size)</p>
<p>​                .setMaxResults(size)</p>
<p>​                .list();</p>
<p>​        return list != null &amp;&amp; list.size() &gt; 0 ? list : Collections.EMPTY_LIST;</p>
<p>​    }</p>
<p>​    /**</p>
<p>​     * 查询满足条件的记录数</p>
<p>​     * @param hql 基于HQL的查询语句</p>
<p>​     * @param params 可变参数列表</p>
<p>​     * @return 满足查询条件的总记录数</p>
<p>​     */</p>
<p>​    protected long getCountByHQL(String hql, Object… params) {</p>
<p>​        return this.getCountByHQL(hql, getParamList(params));</p>
<p>​    }</p>
<p>​    /**</p>
<p>​     * 查询满足条件的记录数</p>
<p>​     * @param hql 基于HQL的查询语句</p>
<p>​     * @param params 参数列表容器</p>
<p>​     * @return 满足查询条件的总记录数</p>
<p>​     */</p>
<p>​    protected long getCountByHQL(String hql, List<object> params) {</object></p>
<p>​        return (Long) createQuery(hql, params).uniqueResult();</p>
<p>​    }</p>
<p>​    // 创建Hibernate查询对象(Query)</p>
<p>​    private Query createQuery(String hql, List<object> params) {</object></p>
<p>​        Query query = sessionFactory.getCurrentSession().createQuery(hql);</p>
<p>​        for(int i = 0; i &lt; params.size(); i++) {</p>
<p>​            query.setParameter(i, params.get(i));</p>
<p>​        }</p>
<p>​        return query;</p>
<p>​    }</p>
<p>​    // 将可变参数列表组装成列表容器</p>
<p>​    private List<object> getParamList(Object… params) {</object></p>
<p>​        List<object> paramList = new ArrayList&lt;&gt;();</object></p>
<p>​        if(params != null) {</p>
<p>​            for(int i = 0; i &lt; params.length; i++) {</p>
<p>​                paramList.add(params[i]);</p>
<p>​            }</p>
<p>​        }</p>
<p>​        return paramList.size() == 0? Collections.EMPTY_LIST : paramList;</p>
<p>​    }</p>
<p>}</p>
<p>package com.jackfrued.comm;</p>
<p>import java.util.List;</p>
<p>/**</p>
<ul>
<li>查询条件的接口</li>
<li><p>@author 骆昊</p>
<p>*</p>
<p>*/</p>
</li>
</ul>
<p>public interface QueryBean {</p>
<p>​    /**</p>
<p>​     * 添加排序字段</p>
<p>​     * @param fieldName 用于排序的字段</p>
<p>​     * @param asc 升序还是降序</p>
<p>​     * @return 查询条件对象自身(方便级联编程)</p>
<p>​     */</p>
<p>​    public QueryBean addOrder(String fieldName, boolean asc);</p>
<p>​    /**</p>
<p>​     * 添加排序字段</p>
<p>​     * @param available 是否添加此排序字段</p>
<p>​     * @param fieldName 用于排序的字段</p>
<p>​     * @param asc 升序还是降序</p>
<p>​     * @return 查询条件对象自身(方便级联编程)</p>
<p>​     */</p>
<p>​    public QueryBean addOrder(boolean available, String fieldName, boolean asc);</p>
<p>​    /**</p>
<p>​     * 添加查询条件</p>
<p>​     * @param condition 条件</p>
<p>​     * @param params 替换掉条件中参数占位符的参数</p>
<p>​     * @return 查询条件对象自身(方便级联编程)</p>
<p>​     */</p>
<p>​    public QueryBean addCondition(String condition, Object… params);</p>
<p>​    /**</p>
<p>​     * 添加查询条件</p>
<p>​     * @param available 是否需要添加此条件</p>
<p>​     * @param condition 条件</p>
<p>​     * @param params 替换掉条件中参数占位符的参数</p>
<p>​     * @return 查询条件对象自身(方便级联编程)</p>
<p>​     */</p>
<p>​    public QueryBean addCondition(boolean available, String condition, Object… params);</p>
<p>​    /**</p>
<p>​     * 获得查询语句</p>
<p>​     * @return 查询语句</p>
<p>​     */</p>
<p>​    public String getQueryString();</p>
<p>​    /**</p>
<p>​     * 获取查询记录数的查询语句</p>
<p>​     * @return 查询记录数的查询语句</p>
<p>​     */</p>
<p>​    public String getCountString();</p>
<p>​    /**</p>
<p>​     * 获得查询参数</p>
<p>​     * @return 查询参数的列表容器</p>
<p>​     */</p>
<p>​    public List<object> getParameters();</object></p>
<p>}</p>
<p>package com.jackfrued.comm;</p>
<p>import java.util.List;</p>
<p>/**</p>
<ul>
<li>查询结果</li>
<li><p>@author 骆昊</p>
<p>*</p>
</li>
<li><p>@param <t> 泛型参数</t></p>
<p>*/</p>
</li>
</ul>
<p>public class QueryResult<t> {</t></p>
<p>​    private List<t> result;     // 持有查询结果的列表容器</t></p>
<p>​    private long totalRecords;  // 查询到的总记录数</p>
<p>​    /**</p>
<p>​     * 构造器</p>
<p>​     */</p>
<p>​    public QueryResult() {</p>
<p>​    }</p>
<p>​    /**</p>
<p>​     * 构造器</p>
<p>​     * @param result 持有查询结果的列表容器</p>
<p>​     * @param totalRecords 查询到的总记录数</p>
<p>​     */</p>
<p>​    public QueryResult(List<t> result, long totalRecords) {</t></p>
<p>​        this.result = result;</p>
<p>​        this.totalRecords = totalRecords;</p>
<p>​    }</p>
<p>​    public List<t> getResult() {</t></p>
<p>​        return result;</p>
<p>​    }</p>
<p>​    public void setResult(List<t> result) {</t></p>
<p>​        this.result = result;</p>
<p>​    }</p>
<p>​    public long getTotalRecords() {</p>
<p>​        return totalRecords;</p>
<p>​    }</p>
<p>​    public void setTotalRecords(long totalRecords) {</p>
<p>​        this.totalRecords = totalRecords;</p>
<p>​    }</p>
<p>}</p>
<p>package com.jackfrued.dao;</p>
<p>import com.jackfrued.comm.QueryResult;</p>
<p>import com.jackfrued.entity.Dept;</p>
<p>/**</p>
<ul>
<li>部门数据访问对象接口</li>
<li><p>@author 骆昊</p>
<p>*</p>
<p>*/</p>
</li>
</ul>
<p>public interface DeptDao extends BaseDao&lt;Dept, Integer&gt; {</p>
<p>​    /**</p>
<p>​     * 分页查询顶级部门</p>
<p>​     * @param page 页码</p>
<p>​     * @param size 页码大小</p>
<p>​     * @return 查询结果对象</p>
<p>​     */</p>
<p>​    public QueryResult<dept> findTopDeptByPage(int page, int size);</dept></p>
<p>}</p>
<p>package com.jackfrued.dao.impl;</p>
<p>import java.util.List;</p>
<p>import org.springframework.stereotype.Repository;</p>
<p>import com.jackfrued.comm.QueryResult;</p>
<p>import com.jackfrued.dao.BaseDaoHibernateImpl;</p>
<p>import com.jackfrued.dao.DeptDao;</p>
<p>import com.jackfrued.entity.Dept;</p>
<p>@Repository</p>
<p>public class DeptDaoImpl extends BaseDaoHibernateImpl&lt;Dept, Integer&gt; implements DeptDao {</p>
<p>​    private static final String HQL_FIND_TOP_DEPT = “ from Dept as d where d.superiorDept is null “;</p>
<p>​    @Override</p>
<p>​    public QueryResult<dept> findTopDeptByPage(int page, int size) {</dept></p>
<p>​        List<dept> list = findByHQLAndPage(HQL_FIND_TOP_DEPT, page, size);</dept></p>
<p>​        long totalRecords = getCountByHQL(“ select count(*) “ + HQL_FIND_TOP_DEPT);</p>
<p>​        return new QueryResult&lt;&gt;(list, totalRecords);</p>
<p>​    }</p>
<p>}</p>
<p>package com.jackfrued.comm;</p>
<p>import java.util.List;</p>
<p>/**</p>
<ul>
<li>分页器</li>
<li><p>@author 骆昊</p>
<p>*</p>
</li>
<li><p>@param <t> 分页数据对象的类型</t></p>
<p>*/</p>
</li>
</ul>
<p>public class PageBean<t> {</t></p>
<p>​    private static final int DEFAUL_INIT_PAGE = 1;</p>
<p>​    private static final int DEFAULT_PAGE_SIZE = 10;</p>
<p>​    private static final int DEFAULT_PAGE_COUNT = 5;</p>
<p>​    private List<t> data;           // 分页数据</t></p>
<p>​    private PageRange pageRange;    // 页码范围</p>
<p>​    private int totalPage;          // 总页数</p>
<p>​    private int size;               // 页面大小</p>
<p>​    private int currentPage;        // 当前页码</p>
<p>​    private int pageCount;          // 页码数量</p>
<p>​    /**</p>
<p>​     * 构造器</p>
<p>​     * @param currentPage 当前页码</p>
<p>​     * @param size 页码大小</p>
<p>​     * @param pageCount 页码数量</p>
<p>​     */</p>
<p>​    public PageBean(int currentPage, int size, int pageCount) {</p>
<p>​        this.currentPage = currentPage &gt; 0 ? currentPage : 1;</p>
<p>​        this.size = size &gt; 0 ? size : DEFAULT_PAGE_SIZE;</p>
<p>​        this.pageCount = pageCount &gt; 0 ? size : DEFAULT_PAGE_COUNT;</p>
<p>​    }</p>
<p>​    /**</p>
<p>​     * 构造器</p>
<p>​     * @param currentPage 当前页码</p>
<p>​     * @param size 页码大小</p>
<p>​     */</p>
<p>​    public PageBean(int currentPage, int size) {</p>
<p>​        this(currentPage, size, DEFAULT_PAGE_COUNT);</p>
<p>​    }</p>
<p>​    /**</p>
<p>​     * 构造器</p>
<p>​     * @param currentPage 当前页码</p>
<p>​     */</p>
<p>​    public PageBean(int currentPage) {</p>
<p>​        this(currentPage, DEFAULT_PAGE_SIZE, DEFAULT_PAGE_COUNT);</p>
<p>​    }</p>
<p>​    /**</p>
<p>​     * 构造器</p>
<p>​     */</p>
<p>​    public PageBean() {</p>
<p>​        this(DEFAUL_INIT_PAGE, DEFAULT_PAGE_SIZE, DEFAULT_PAGE_COUNT);</p>
<p>​    }</p>
<p>​    public List<t> getData() {</t></p>
<p>​        return data;</p>
<p>​    }</p>
<p>​    public int getStartPage() {</p>
<p>​        return pageRange != null ? pageRange.getStartPage() : 1;</p>
<p>​    }</p>
<p>​    public int getEndPage() {</p>
<p>​        return pageRange != null ? pageRange.getEndPage() : 1;</p>
<p>​    }</p>
<p>​    public long getTotalPage() {</p>
<p>​        return totalPage;</p>
<p>​    }</p>
<p>​    public int getSize() {</p>
<p>​        return size;</p>
<p>​    }</p>
<p>​    public int getCurrentPage() {</p>
<p>​        return currentPage;</p>
<p>​    }</p>
<p>​    /**</p>
<p>​     * 将查询结果转换为分页数据</p>
<p>​     * @param queryResult 查询结果对象</p>
<p>​     */</p>
<p>​    public void transferQueryResult(QueryResult<t> queryResult) {</t></p>
<p>​        long totalRecords = queryResult.getTotalRecords();</p>
<p>​        data = queryResult.getResult();</p>
<p>​        totalPage = (int) ((totalRecords + size - 1) / size); </p>
<p>​        totalPage = totalPage &gt;= 0 ? totalPage : Integer.MAX_VALUE;</p>
<p>​        this.pageRange = new PageRange(pageCount, currentPage, totalPage);</p>
<p>​    }</p>
<p>}</p>
<p>package com.jackfrued.comm;</p>
<p>/**</p>
<ul>
<li>页码范围</li>
<li><p>@author 骆昊</p>
<p>*</p>
<p>*/</p>
</li>
</ul>
<p>public class PageRange {</p>
<p>​    private int startPage;  // 起始页码</p>
<p>​    private int endPage;    // 终止页码</p>
<p>​    /**</p>
<p>​     * 构造器</p>
<p>​     * @param pageCount 总共显示几个页码</p>
<p>​     * @param currentPage 当前页码</p>
<p>​     * @param totalPage 总页数</p>
<p>​     */</p>
<p>​    public PageRange(int pageCount, int currentPage, int totalPage) {</p>
<p>​        startPage = currentPage - (pageCount - 1) / 2;</p>
<p>​        endPage = currentPage + pageCount / 2;</p>
<p>​        if(startPage &lt; 1) {</p>
<p>​            startPage = 1;</p>
<p>​            endPage = totalPage &gt; pageCount ? pageCount : totalPage;</p>
<p>​        }</p>
<p>​        if (endPage &gt; totalPage) {</p>
<p>​            endPage = totalPage;</p>
<p>​            startPage = (endPage - pageCount &gt; 0) ? endPage - pageCount + 1 : 1;</p>
<p>​        }</p>
<p>​    }</p>
<p>​    /**</p>
<p>​     * 获得起始页页码</p>
<p>​     * @return 起始页页码</p>
<p>​     */</p>
<p>​    public int getStartPage() {</p>
<p>​        return startPage;</p>
<p>​    }</p>
<p>​    /**</p>
<p>​     * 获得终止页页码</p>
<p>​     * @return 终止页页码</p>
<p>​     */</p>
<p>​    public int getEndPage() {</p>
<p>​        return endPage;</p>
<p>​    }</p>
<p>}</p>
<p>package com.jackfrued.biz;</p>
<p>import com.jackfrued.comm.PageBean;</p>
<p>import com.jackfrued.entity.Dept;</p>
<p>/**</p>
<ul>
<li>部门业务逻辑接口</li>
<li><p>@author 骆昊</p>
<p>*</p>
<p>*/</p>
</li>
</ul>
<p>public interface DeptService {</p>
<p>​    /**</p>
<p>​     * 创建新的部门</p>
<p>​     * @param department 部门对象</p>
<p>​     * @return 创建成功返回true否则返回false</p>
<p>​     */</p>
<p>​    public boolean createNewDepartment(Dept department);</p>
<p>​    /**</p>
<p>​     * 删除指定部门</p>
<p>​     * @param id 要删除的部门的编号</p>
<p>​     * @return 删除成功返回true否则返回false</p>
<p>​     */</p>
<p>​    public boolean deleteDepartment(Integer id);</p>
<p>​    /**</p>
<p>​     * 分页获取顶级部门</p>
<p>​     * @param page 页码</p>
<p>​     * @param size 页码大小</p>
<p>​     * @return 部门对象的分页器对象</p>
<p>​     */</p>
<p>​    public PageBean<dept> getTopDeptByPage(int page, int size);</dept></p>
<p>}</p>
<p>package com.jackfrued.biz.impl;</p>
<p>import org.springframework.beans.factory.annotation.Autowired;</p>
<p>import org.springframework.stereotype.Service;</p>
<p>import org.springframework.transaction.annotation.Transactional;</p>
<p>import com.jackfrued.biz.DeptService;</p>
<p>import com.jackfrued.comm.PageBean;</p>
<p>import com.jackfrued.comm.QueryResult;</p>
<p>import com.jackfrued.dao.DeptDao;</p>
<p>import com.jackfrued.entity.Dept;</p>
<p>@Service</p>
<p>@Transactional  // 声明式事务的注解</p>
<p>public class DeptServiceImpl implements DeptService {</p>
<p>​    @Autowired</p>
<p>​    private DeptDao deptDao;</p>
<p>​    @Override</p>
<p>​    public boolean createNewDepartment(Dept department) {</p>
<p>​        return deptDao.save(department) != null;</p>
<p>​    }</p>
<p>​    @Override</p>
<p>​    public boolean deleteDepartment(Integer id) {</p>
<p>​        return deptDao.deleteById(id);</p>
<p>​    }</p>
<p>​    @Override</p>
<p>​    public PageBean<dept> getTopDeptByPage(int page, int size) {</dept></p>
<p>​        QueryResult<dept> queryResult = deptDao.findTopDeptByPage(page, size);</dept></p>
<p>​        PageBean<dept> pageBean = new PageBean&lt;&gt;(page, size);</dept></p>
<p>​        pageBean.transferQueryResult(queryResult);</p>
<p>​        return pageBean;</p>
<p>​    }</p>
<p>}</p>
<h3 id="如何在Web项目中配置Spring的IoC容器？"><a href="#如何在Web项目中配置Spring的IoC容器？" class="headerlink" title="如何在Web项目中配置Spring的IoC容器？"></a>如何在Web项目中配置Spring的IoC容器？</h3><p> 答：如果需要在Web项目中使用Spring的IoC容器，可以在Web项目配置文件web.xml中做出如下配置：</p>
<p><context-param></context-param></p>
<p>​    <param-name>contextConfigLocation</param-name></p>
<p>​    <param-value>classpath:applicationContext.xml</param-value></p>
<p></p>
<listener><br><br>​    <listener-class><br><br>​        org.springframework.web.context.ContextLoaderListener<br><br>​    </listener-class><br><br></listener>



<h3 id="如何在Spring-IoC容器中配置数据源？"><a href="#如何在Spring-IoC容器中配置数据源？" class="headerlink" title="如何在Spring IoC容器中配置数据源？"></a>如何在Spring IoC容器中配置数据源？</h3><p>答：<br>DBCP配置：</p>
<bean id="dataSource" ​ class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"><br><br>​    <property name="driverClassName" value="${jdbc.driverClassName}"><br><br>​    <property name="url" value="${jdbc.url}"><br><br>​    <property name="username" value="${jdbc.username}"><br><br>​    <property name="password" value="${jdbc.password}"><br><br></property></property></property></property></bean>



<p>&lt;context:property-placeholder location=”jdbc.properties”/&gt;</p>
<p>C3P0配置：</p>
<bean id="dataSource" ​ class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close"><br><br>​    <property name="driverClass" value="${jdbc.driverClassName}"><br><br>​    <property name="jdbcUrl" value="${jdbc.url}"><br><br>​    <property name="user" value="${jdbc.username}"><br><br>​    <property name="password" value="${jdbc.password}"><br><br></property></property></property></property></bean>



<p>&lt;context:property-placeholder location=”jdbc.properties”/&gt;</p>
<p>提示： DBCP的详细配置在第153题中已经完整的展示过了。</p>
<h3 id="如何配置配置事务增强？"><a href="#如何配置配置事务增强？" class="headerlink" title="如何配置配置事务增强？"></a>如何配置配置事务增强？</h3><p>答：</p>
<p>&lt;?xml version=”1.0” encoding=”UTF-8”?&gt;</p>
<beans xmlns="http://www.springframework.org/schema/beans" ​ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx" xsi:schemalocation="

​     http://www.springframework.org/schema/beans

​     http://www.springframework.org/schema/beans/spring-beans.xsd

​     http://www.springframework.org/schema/tx

​     http://www.springframework.org/schema/tx/spring-tx.xsd

​     http://www.springframework.org/schema/aop

​     http://www.springframework.org/schema/aop/spring-aop.xsd"><br><br><br><br>  <!-- this is the service object that we want to make transactional --><br><br>  <bean id="fooService" class="x.y.service.DefaultFooService"><br><br><br><br>  <!-- the transactional advice --><br><br>  &lt;tx:advice id=”txAdvice” transaction-manager=”txManager”&gt;<br><br>  <!-- the transactional semantics... --><br><br>  tx:attributes<br><br>​    <!-- all methods starting with 'get' are read-only --><br><br>​    &lt;tx:method name=”get<em>“ read-only=”true”/&gt;<br><br>​    <!-- other methods use the default transaction settings (see below) --><br><br>​    &lt;tx:method name=”</em>“/&gt;<br><br>  /tx:attributes<br><br>  /tx:advice<br><br><br><br>  <!-- ensure that the above transactional advice runs for any execution

​    of an operation defined by the FooService interface --><br><br>  aop:config<br><br>  &lt;aop:pointcut id=”fooServiceOperation”<br><br>​    expression=”execution(<em> x.y.service.FooService.</em>(..))”/&gt;<br><br>  &lt;aop:advisor advice-ref=”txAdvice” pointcut-ref=”fooServiceOperation”/&gt;<br><br>  /aop:config<br><br><br><br>  <!-- don't forget the DataSource --><br><br>  <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" ​ destroy-method="close"><br><br>  <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"><br><br>  <property name="url" value="jdbc:oracle:thin:@localhost:1521:orcl"><br><br>  <property name="username" value="scott"><br><br>  <property name="password" value="tiger"><br><br>  </property></property></property></property></bean><br><br><br><br>  <!-- similarly, don't forget the PlatformTransactionManager --><br><br>  <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"><br><br>  <property name="dataSource" ref="dataSource"><br><br>  </property></bean><br><br><br><br>  <!-- other <bean/> definitions here --><br><br><br><br></bean></beans>

<h3 id="选择使用Spring框架的原因（Spring框架为企业级开发带来的好处有哪些）？"><a href="#选择使用Spring框架的原因（Spring框架为企业级开发带来的好处有哪些）？" class="headerlink" title="选择使用Spring框架的原因（Spring框架为企业级开发带来的好处有哪些）？"></a>选择使用Spring框架的原因（Spring框架为企业级开发带来的好处有哪些）？</h3><p>答：可以从以下几个方面作答： </p>
<ul>
<li>非侵入式：支持基于POJO的编程模式，不强制性的要求实现Spring框架中的接口或继承Spring框架中的类。 </li>
<li>IoC容器：IoC容器帮助应用程序管理对象以及对象之间的依赖关系，对象之间的依赖关系如果发生了改变只需要修改配置文件而不是修改代码，因为代码的修改可能意味着项目的重新构建和完整的回归测试。有了IoC容器，程序员再也不需要自己编写工厂、单例，这一点特别符合Spring的精神”不要重复的发明轮子”。 </li>
<li>AOP（面向切面编程）：将所有的横切关注功能封装到切面（aspect）中，通过配置的方式将横切关注功能动态添加到目标代码上，进一步实现了业务逻辑和系统服务之间的分离。另一方面，有了AOP程序员可以省去很多自己写代理类的工作。 </li>
<li>MVC：Spring的MVC框架是非常优秀的，从各个方面都可以甩Struts 2几条街，为Web表示层提供了更好的解决方案。 </li>
<li>事务管理：Spring以宽广的胸怀接纳多种持久层技术，并且为其提供了声明式的事务管理，在不需要任何一行代码的情况下就能够完成事务管理。 </li>
<li>其他：选择Spring框架的原因还远不止于此，Spring为Java企业级开发提供了一站式选择，你可以在需要的时候使用它的部分和全部，更重要的是，你甚至可以在感觉不到Spring存在的情况下，在你的项目中使用Spring提供的各种优秀的功能。</li>
</ul>
<h3 id="Spring-IoC容器配置Bean的方式？"><a href="#Spring-IoC容器配置Bean的方式？" class="headerlink" title="Spring IoC容器配置Bean的方式？"></a>Spring IoC容器配置Bean的方式？</h3><p>答： </p>
<ul>
<li>基于XML文件进行配置。 </li>
<li>基于注解进行配置。 </li>
<li>基于Java程序进行配置（Spring 3+）</li>
</ul>
<p>package com.jackfrued.bean;</p>
<p>import org.springframework.beans.factory.annotation.Autowired;</p>
<p>import org.springframework.stereotype.Component;</p>
<p>@Component</p>
<p>public class Person {</p>
<p>​    private String name;</p>
<p>​    private int age;</p>
<p>​    @Autowired</p>
<p>​    private Car car;</p>
<p>​    public Person(String name, int age) {</p>
<p>​        this.name = name;</p>
<p>​        this.age = age;</p>
<p>​    }</p>
<p>​    public void setCar(Car car) {</p>
<p>​        this.car = car;</p>
<p>​    }</p>
<p>​    @Override</p>
<p>​    public String toString() {</p>
<p>​        return “Person [name=” + name + “, age=” + age + “, car=” + car + “]”;</p>
<p>​    }</p>
<p>}</p>
<p>package com.jackfrued.bean;</p>
<p>import org.springframework.stereotype.Component;</p>
<p>@Component</p>
<p>public class Car {</p>
<p>​    private String brand;</p>
<p>​    private int maxSpeed;</p>
<p>​    public Car(String brand, int maxSpeed) {</p>
<p>​        this.brand = brand;</p>
<p>​        this.maxSpeed = maxSpeed;</p>
<p>​    }</p>
<p>​    @Override</p>
<p>​    public String toString() {</p>
<p>​        return “Car [brand=” + brand + “, maxSpeed=” + maxSpeed + “]”;</p>
<p>​    }</p>
<p>}</p>
<p>package com.jackfrued.config;</p>
<p>import org.springframework.context.annotation.Bean;</p>
<p>import org.springframework.context.annotation.Configuration;</p>
<p>import com.jackfrued.bean.Car;</p>
<p>import com.jackfrued.bean.Person;</p>
<p>@Configuration</p>
<p>public class AppConfig {</p>
<p>​    @Bean</p>
<p>​    public Car car() {</p>
<p>​        return new Car(“Benz”, 320);</p>
<p>​    }</p>
<p>​    @Bean</p>
<p>​    public Person person() {</p>
<p>​        return new Person(“骆昊”, 34);</p>
<p>​    }</p>
<p>}</p>
<p>package com.jackfrued.test;</p>
<p>import org.springframework.context.ConfigurableApplicationContext;</p>
<p>import org.springframework.context.annotation.AnnotationConfigApplicationContext;</p>
<p>import com.jackfrued.bean.Person;</p>
<p>import com.jackfrued.config.AppConfig;</p>
<p>class Test {</p>
<p>​    public static void main(String[] args) {</p>
<p>​        // TWR (Java 7+)</p>
<p>​        try(ConfigurableApplicationContext factory = new AnnotationConfigApplicationContext(AppConfig.class)) {</p>
<p>​            Person person = factory.getBean(Person.class);</p>
<p>​            System.out.println(person);</p>
<p>​        }</p>
<p>​    }</p>
<p>}</p>
<h3 id="阐述Spring框架中Bean的生命周期？"><a href="#阐述Spring框架中Bean的生命周期？" class="headerlink" title="阐述Spring框架中Bean的生命周期？"></a>阐述Spring框架中Bean的生命周期？</h3><p>答：<br>① Spring IoC容器找到关于Bean的定义并实例化该Bean。<br>② Spring IoC容器对Bean进行依赖注入。<br>③ 如果Bean实现了BeanNameAware接口，则将该Bean的id传给setBeanName方法。<br>④ 如果Bean实现了BeanFactoryAware接口，则将BeanFactory对象传给setBeanFactory方法。<br>⑤ 如果Bean实现了BeanPostProcessor接口，则调用其postProcessBeforeInitialization方法。<br>⑥ 如果Bean实现了InitializingBean接口，则调用其afterPropertySet方法。<br>⑦ 如果有和Bean关联的BeanPostProcessors对象，则这些对象的postProcessAfterInitialization方法被调用。<br>⑧ 当销毁Bean实例时，如果Bean实现了DisposableBean接口，则调用其destroy方法。</p>
<h3 id="依赖注入时如何注入集合属性？"><a href="#依赖注入时如何注入集合属性？" class="headerlink" title="依赖注入时如何注入集合属性？"></a>依赖注入时如何注入集合属性？</h3><p>答：可以在定义Bean属性时，通过<list> / <set> / <map> / <props>分别为其注入列表、集合、映射和键值都是字符串的映射属性。</props></map></set></list></p>
<h3 id="Spring中的自动装配有哪些限制？"><a href="#Spring中的自动装配有哪些限制？" class="headerlink" title="Spring中的自动装配有哪些限制？"></a>Spring中的自动装配有哪些限制？</h3><p> 答： </p>
<ul>
<li>如果使用了构造器注入或者setter注入，那么将覆盖自动装配的依赖关系。 </li>
<li>基本数据类型的值、字符串字面量、类字面量无法使用自动装配来注入。 </li>
<li>优先考虑使用显式的装配来进行更精确的依赖注入而不是使用自动装配。</li>
</ul>
<h3 id="在Web项目中如何获得Spring的IoC容器？"><a href="#在Web项目中如何获得Spring的IoC容器？" class="headerlink" title="在Web项目中如何获得Spring的IoC容器？"></a>在Web项目中如何获得Spring的IoC容器？</h3><p>答：</p>
<p>WebApplicationContext ctx = </p>
<p>WebApplicationContextUtils.getWebApplicationContext(servletContext);</p>
<h3 id="Spring由哪些模块组成？"><a href="#Spring由哪些模块组成？" class="headerlink" title="Spring由哪些模块组成？"></a>Spring由哪些模块组成？</h3><p>以下是Spring 框架的基本模块：</p>
<p>Core module</p>
<p>Bean module</p>
<p>Context module</p>
<p>Expression Language module</p>
<p>JDBC module</p>
<p>ORM module</p>
<p>OXM module</p>
<p>Java Messaging Service(JMS) module</p>
<p>Transaction module</p>
<p>Web module</p>
<p>Web-Servlet module</p>
<p>Web-Struts module</p>
<p>Web-Portlet module</p>
<h3 id="【Spring】什么是Spring-IOC-容器？"><a href="#【Spring】什么是Spring-IOC-容器？" class="headerlink" title="【Spring】什么是Spring IOC 容器？"></a>【Spring】<strong>什么是Spring IOC 容器？</strong></h3><p>Spring IOC 负责创建对象，管理对象（通过依赖注入（DI），装配对象，配置对象，并且管理这些对象的整个生命周期。</p>
<h3 id="【Spring】IOC的优点是什么？"><a href="#【Spring】IOC的优点是什么？" class="headerlink" title="【Spring】IOC的优点是什么？"></a>【Spring】<strong>IOC的优点是什么？</strong></h3><p>IOC 或 依赖注入把应用的代码量降到最低。它使应用容易测试，单元测试不再需要单例和JNDI查找机制。最小的代价和最小的侵入性使松散耦合得以实现。IOC容器支持加载服务时的饿汉式初始化和懒加载。</p>
<h3 id="【Spring】ApplicationContext通常的实现是什么？"><a href="#【Spring】ApplicationContext通常的实现是什么？" class="headerlink" title="【Spring】ApplicationContext通常的实现是什么？"></a>【Spring】<strong>ApplicationContext通常的实现是什么？</strong></h3><p>FileSystemXmlApplicationContext ：此容器从一个XML文件中加载beans的定义，XML Bean 配置文件的全路径名必须提供给它的构造函数。</p>
<p>ClassPathXmlApplicationContext：此容器也从一个XML文件中加载beans的定义，这里，你需要正确设置classpath因为这个容器将在classpath里找bean配置。</p>
<p>WebXmlApplicationContext：此容器加载一个XML文件，此文件定义了一个WEB应用的所有bean。</p>
<h3 id="【Spring】Bean-工厂和-Application-contexts-有什么区别？"><a href="#【Spring】Bean-工厂和-Application-contexts-有什么区别？" class="headerlink" title="【Spring】Bean 工厂和 Application contexts  有什么区别？"></a>【Spring】<strong>Bean 工厂和 Application contexts  有什么区别？</strong></h3><p>Application contexts提供一种方法处理文本消息，一个通常的做法是加载文件资源（比如镜像），它们可以向注册为监听器的bean发布事件。另外，在容器或容器内的对象上执行的那些不得不由bean工厂以程序化方式处理的操作，可以在Application contexts中以声明的方式处理。Application contexts实现了MessageSource接口，该接口的实现以可插拔的方式提供获取本地化消息的方法。</p>
<h3 id="【Spring】什么是Spring的依赖注入？"><a href="#【Spring】什么是Spring的依赖注入？" class="headerlink" title="【Spring】什么是Spring的依赖注入？"></a>【Spring】<strong>什么是Spring的依赖注入？</strong></h3><p>依赖注入，是IOC的一个方面，是个通常的概念，它有多种解释。这概念是说你不用创建对象，而只需要描述它如何被创建。你不在代码里直接组装你的组件和服务，但是要在配置文件里描述哪些组件需要哪些服务，之后一个容器（IOC容器）负责把他们组装起来。</p>
<h3 id="【Spring】有哪些不同类型的IOC（依赖注入）方式？"><a href="#【Spring】有哪些不同类型的IOC（依赖注入）方式？" class="headerlink" title="【Spring】有哪些不同类型的IOC（依赖注入）方式？"></a>【Spring】<strong>有哪些不同类型的IOC（依赖注入）方式？</strong></h3><p>构造器依赖注入：构造器依赖注入通过容器触发一个类的构造器来实现的，该类有一系列参数，每个参数代表一个对其他类的依赖。</p>
<p>Setter方法注入：Setter方法注入是容器通过调用无参构造器或无参static工厂 方法实例化bean之后，调用该bean的setter方法，即实现了基于setter的依赖注入。</p>
<h3 id="【Spring】哪种依赖注入方式你建议使用，构造器注入，还是-Setter方法注入？"><a href="#【Spring】哪种依赖注入方式你建议使用，构造器注入，还是-Setter方法注入？" class="headerlink" title="【Spring】哪种依赖注入方式你建议使用，构造器注入，还是 Setter方法注入？"></a>【Spring】<strong>哪种依赖注入方式你建议使用，构造器注入，还是 Setter方法注入？</strong></h3><p>你两种依赖方式都可以使用，构造器注入和Setter方法注入。最好的解决方案是用构造器参数实现强制依赖，setter方法实现可选依赖。</p>
<h3 id="【Spring】什么是Spring-beans？"><a href="#【Spring】什么是Spring-beans？" class="headerlink" title="【Spring】什么是Spring beans？"></a>【Spring】<strong>什么是Spring beans？</strong></h3><p>Spring beans 是那些形成Spring应用的主干的java对象。它们被Spring IOC容器初始化，装配，和管理。这些beans通过容器中配置的元数据创建。比如，以XML文件中<bean> 的形式定义。</bean></p>
<p>Spring 框架定义的beans都是单件beans。在bean tag中有个属性”singleton”，如果它被赋为TRUE，bean 就是单件，否则就是一个 prototype bean。默认是TRUE，所以所有在Spring框架中的beans 缺省都是单件。</p>
<h3 id="【Spring】一个-Spring-Bean-定义-包含什么？"><a href="#【Spring】一个-Spring-Bean-定义-包含什么？" class="headerlink" title="【Spring】一个 Spring Bean 定义 包含什么？"></a>【Spring】<strong>一个 Spring Bean 定义 包含什么？</strong></h3><p>一个Spring Bean 的定义包含容器必知的所有配置元数据，包括如何创建一个bean，它的生命周期详情及它的依赖。</p>
<h3 id="【Spring】如何给Spring-容器提供配置元数据？"><a href="#【Spring】如何给Spring-容器提供配置元数据？" class="headerlink" title="【Spring】如何给Spring 容器提供配置元数据？"></a>【Spring】<strong>如何给Spring 容器提供配置元数据？</strong></h3><p>这里有三种重要的方法给Spring 容器提供配置元数据。</p>
<p>XML配置文件。</p>
<p>基于注解的配置。</p>
<p>基于java的配置。</p>
<h3 id="【Spring】解释Spring支持的几种bean的作用域"><a href="#【Spring】解释Spring支持的几种bean的作用域" class="headerlink" title="【Spring】解释Spring支持的几种bean的作用域"></a>【Spring】<strong>解释Spring支持的几种bean的作用域</strong></h3><p>Spring框架支持以下五种bean的作用域：</p>
<p>singleton : bean在每个Spring ioc 容器中只有一个实例。</p>
<p>prototype：一个bean的定义可以有多个实例。</p>
<p>request：每次http请求都会创建一个bean，该作用域仅在基于web的Spring ApplicationContext情形下有效。</p>
<p>session：在一个HTTP Session中，一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。</p>
<p>global-session：在一个全局的HTTP Session中，一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。</p>
<p>缺省的Spring bean 的作用域是Singleton。</p>
<h3 id="【Spring】Spring框架中的单例bean是线程安全的吗？"><a href="#【Spring】Spring框架中的单例bean是线程安全的吗？" class="headerlink" title="【Spring】Spring框架中的单例bean是线程安全的吗？"></a>【Spring】<strong>Spring框架中的单例bean是线程安全的吗？</strong></h3><p>不，Spring框架中的单例bean不是线程安全的。</p>
<h3 id="【Spring】解释Spring框架中bean的生命周期"><a href="#【Spring】解释Spring框架中bean的生命周期" class="headerlink" title="【Spring】解释Spring框架中bean的生命周期"></a>【Spring】<strong>解释Spring框架中bean的生命周期</strong></h3><p>Spring容器 从XML 文件中读取bean的定义，并实例化bean。</p>
<p>Spring根据bean的定义填充所有的属性。</p>
<p>如果bean实现了BeanNameAware 接口，Spring 传递bean 的ID 到 setBeanName方法。</p>
<p>如果Bean 实现了 BeanFactoryAware 接口， Spring传递beanfactory 给setBeanFactory 方法。</p>
<p>如果有任何与bean相关联的BeanPostProcessors，Spring会在postProcesserBeforeInitialization()方法内调用它们。</p>
<p>如果bean实现IntializingBean了，调用它的afterPropertySet方法，如果bean声明了初始化方法，调用此初始化方法。</p>
<p>如果有BeanPostProcessors 和bean 关联，这些bean的postProcessAfterInitialization() 方法将被调用。</p>
<p>如果bean实现了 DisposableBean，它将调用destroy()方法。</p>
<h3 id="【Spring】哪些是重要的bean生命周期方法？-你能重载它们吗？"><a href="#【Spring】哪些是重要的bean生命周期方法？-你能重载它们吗？" class="headerlink" title="【Spring】哪些是重要的bean生命周期方法？ 你能重载它们吗？"></a>【Spring】<strong>哪些是重要的bean生命周期方法？ 你能重载它们吗？</strong></h3><p>有两个重要的bean 生命周期方法，第一个是setup ， 它是在容器加载bean的时候被调用。第二个方法是 teardown  它是在容器卸载类的时候被调用。</p>
<p>The bean 标签有两个重要的属性（init-method和destroy-method）。用它们你可以自己定制初始化和注销方法。它们也有相应的注解（@PostConstruct和@PreDestroy）。</p>
<h3 id="【Spring】在-Spring中如何注入一个java集合？"><a href="#【Spring】在-Spring中如何注入一个java集合？" class="headerlink" title="【Spring】在 Spring中如何注入一个java集合？"></a>【Spring】<strong>在 Spring中如何注入一个java集合？</strong></h3><p>Spring提供以下几种集合的配置元素：</p>
<p><list>类型用于注入一列值，允许有相同的值。</list></p>
<p><set> 类型用于注入一组值，不允许有相同的值。</set></p>
<p><map> 类型用于注入一组键值对，键和值都可以为任意类型。</map></p>
<p><props>类型用于注入一组键值对，键和值都只能为String类型。</props></p>
<h3 id="【Spring】什么是bean装配？"><a href="#【Spring】什么是bean装配？" class="headerlink" title="【Spring】什么是bean装配？"></a>【Spring】<strong>什么是bean装配？</strong></h3><p>装配，或bean 装配是指在Spring 容器中把bean组装到一起，前提是容器需要知道bean的依赖关系，如何通过依赖注入来把它们装配到一起。</p>
<h3 id="【Spring】什么是bean的自动装配？"><a href="#【Spring】什么是bean的自动装配？" class="headerlink" title="【Spring】什么是bean的自动装配？"></a>【Spring】<strong>什么是bean的自动装配？</strong></h3><p>Spring 容器能够自动装配相互合作的bean，这意味着容器不需要<constructor-arg>和<property>配置，能通过Bean工厂自动处理bean之间的协作。</property></constructor-arg></p>
<h3 id="【Spring】解释不同方式的自动装配"><a href="#【Spring】解释不同方式的自动装配" class="headerlink" title="【Spring】解释不同方式的自动装配"></a>【Spring】<strong>解释不同方式的自动装配</strong></h3><p>有五种自动装配的方式，可以用来指导Spring容器用自动装配方式来进行依赖注入</p>
<p>no：默认的方式是不进行自动装配，通过显式设置ref 属性来进行装配。</p>
<p>byName：通过参数名 自动装配，Spring容器在配置文件中发现bean的autowire属性被设置成byname，之后容器试图匹配、装配和该bean的属性具有相同名字的bean。</p>
<p>byType：通过参数类型自动装配，Spring容器在配置文件中发现bean的autowire属性被设置成byType，之后容器试图匹配、装配和该bean的属性具有相同类型的bean。如果有多个bean符合条件，则抛出错误。</p>
<p>constructor：这个方式类似于byType， 但是要提供给构造器参数，如果没有确定的带参数的构造器参数类型，将会抛出异常。</p>
<p>autodetect：首先尝试使用constructor来自动装配，如果无法工作，则使用byType方式。</p>
<h3 id="【Spring】自动装配有哪些局限性？"><a href="#【Spring】自动装配有哪些局限性？" class="headerlink" title="【Spring】自动装配有哪些局限性？"></a>【Spring】<strong>自动装配有哪些局限性？</strong></h3><p>自动装配的局限性是：</p>
<p>重写：你仍需用 <constructor-arg>和 <property> 配置来定义依赖，意味着总要重写自动装配。</property></constructor-arg></p>
<p>基本数据类型：你不能自动装配简单的属性，如基本数据类型，String字符串，和类。</p>
<p>模糊特性：自动装配不如显式装配精确，如果有可能，建议使用显式装配。</p>
<h3 id="【Spring】你可以在Spring中注入一个null-和一个空字符串吗？"><a href="#【Spring】你可以在Spring中注入一个null-和一个空字符串吗？" class="headerlink" title="【Spring】你可以在Spring中注入一个null 和一个空字符串吗？"></a>【Spring】<strong>你可以在Spring中注入一个null 和一个空字符串吗？</strong></h3><p>可以</p>
<h3 id="【Spring】什么是基于Java的Spring注解配置-给一些注解的例子"><a href="#【Spring】什么是基于Java的Spring注解配置-给一些注解的例子" class="headerlink" title="【Spring】什么是基于Java的Spring注解配置? 给一些注解的例子"></a>【Spring】<strong>什么是基于Java的Spring注解配置? 给一些注解的例子</strong></h3><p>基于Java的配置，允许你在少量的Java注解的帮助下，进行你的大部分Spring配置而非通过XML文件。</p>
<p>以@Configuration 注解为例，它用来标记类可以当做一个bean的定义，被Spring IOC容器使用。另一个例子是@Bean注解，它表示此方法将要返回一个对象，作为一个bean注册进Spring应用上下文。点击这里学习JAVA几大元注解。</p>
<h3 id="【Spring】什么是基于注解的容器配置？"><a href="#【Spring】什么是基于注解的容器配置？" class="headerlink" title="【Spring】什么是基于注解的容器配置？"></a>【Spring】<strong>什么是基于注解的容器配置？</strong></h3><p>相对于XML文件，注解型的配置依赖于通过字节码元数据装配组件，而非尖括号的声明。</p>
<p>开发者通过在相应的类，方法或属性上使用注解的方式，直接组件类中进行配置，而不是使用xml表述bean的装配关系。</p>
<h3 id="【Spring】怎样开启注解装配？"><a href="#【Spring】怎样开启注解装配？" class="headerlink" title="【Spring】怎样开启注解装配？"></a>【Spring】<strong>怎样开启注解装配？</strong></h3><p>注解装配在默认情况下是不开启的，为了使用注解装配，我们必须在Spring配置文件中配置 context:annotation-config/元素。</p>
<h3 id="【Spring】-Required-注解"><a href="#【Spring】-Required-注解" class="headerlink" title="【Spring】@Required  注解"></a>【Spring】<strong>@Required  注解</strong></h3><p>这个注解表明bean的属性必须在配置的时候设置，通过一个bean定义的显式的属性值或通过自动装配，若@Required注解的bean属性未被设置，容器将抛出BeanInitializationException。</p>
<h3 id="【Spring】-Autowired-注解"><a href="#【Spring】-Autowired-注解" class="headerlink" title="【Spring】@Autowired 注解"></a>【Spring】<strong>@Autowired 注解</strong></h3><p>@Autowired 注解提供了更细粒度的控制，包括在何处以及如何完成自动装配。它的用法和@Required一样，修饰setter方法、构造器、属性或者具有任意名称和/或多个参数的PN方法。</p>
<h3 id="【Spring】-Qualifier-注解"><a href="#【Spring】-Qualifier-注解" class="headerlink" title="【Spring】@Qualifier 注解"></a>【Spring】<strong>@Qualifier 注解</strong></h3><p>当有多个相同类型的bean却只有一个需要自动装配时，将@Qualifier 注解和@Autowire 注解结合使用以消除这种混淆，指定需要装配的确切的bean。</p>
<h3 id="【Spring】在Spring框架中如何更有效地使用JDBC？"><a href="#【Spring】在Spring框架中如何更有效地使用JDBC？" class="headerlink" title="【Spring】在Spring框架中如何更有效地使用JDBC？"></a>【Spring】<strong>在Spring框架中如何更有效地使用JDBC？</strong></h3><p>使用SpringJDBC 框架，资源管理和错误处理的代价都会被减轻。所以开发者只需写statements 和 queries从数据存取数据，JDBC也可以在Spring框架提供的模板类的帮助下更有效地被使用，这个模板叫JdbcTemplate （例子见这里here）</p>
<h3 id="【Spring】-JdbcTemplate"><a href="#【Spring】-JdbcTemplate" class="headerlink" title="【Spring】 JdbcTemplate"></a>【Spring】 JdbcTemplate</h3><p>JdbcTemplate 类提供了很多便利的方法解决诸如把数据库数据转变成基本数据类型或对象，执行写好的或可调用的数据库操作语句，提供自定义的数据错误处理。</p>
<h3 id="【Spring】Spring对DAO的支持"><a href="#【Spring】Spring对DAO的支持" class="headerlink" title="【Spring】Spring对DAO的支持"></a>【Spring】<strong>Spring对DAO的支持</strong></h3><p>Spring对数据访问对象（DAO）的支持旨在简化它和数据访问技术如JDBC，Hibernate or JDO 结合使用。这使我们可以方便切换持久层。编码时也不用担心会捕获每种技术特有的异常。</p>
<h3 id="【Spring】使用Spring通过什么方式访问Hibernate？"><a href="#【Spring】使用Spring通过什么方式访问Hibernate？" class="headerlink" title="【Spring】使用Spring通过什么方式访问Hibernate？"></a>【Spring】<strong>使用Spring通过什么方式访问Hibernate？</strong></h3><p>在Spring中有两种方式访问Hibernate：</p>
<p>控制反转  Hibernate Template和 Callback</p>
<p>继承 HibernateDAOSupport提供一个AOP 拦截器</p>
<h3 id="【Spring】Spring支持的ORM"><a href="#【Spring】Spring支持的ORM" class="headerlink" title="【Spring】Spring支持的ORM"></a>【Spring】<strong>Spring支持的ORM</strong></h3><p>Spring支持以下ORM：</p>
<p>Hibernate</p>
<p>iBatis</p>
<p>JPA (Java Persistence API)</p>
<p>TopLink</p>
<p>JDO (Java Data Objects)</p>
<p>OJB</p>
<h3 id="【Spring】如何通过HibernateDaoSupport将Spring和Hibernate结合起来？"><a href="#【Spring】如何通过HibernateDaoSupport将Spring和Hibernate结合起来？" class="headerlink" title="【Spring】如何通过HibernateDaoSupport将Spring和Hibernate结合起来？"></a>【Spring】<strong>如何通过HibernateDaoSupport将Spring和Hibernate结合起来？</strong></h3><p>用Spring的 SessionFactory 调用 LocalSessionFactory。集成过程分三步：</p>
<p>配置the Hibernate SessionFactory</p>
<p>继承HibernateDaoSupport实现一个DAO</p>
<p>在AOP支持的事务中装配</p>
<h3 id="【Spring】Spring支持的事务管理类型"><a href="#【Spring】Spring支持的事务管理类型" class="headerlink" title="【Spring】Spring支持的事务管理类型"></a>【Spring】<strong>Spring支持的事务管理类型</strong></h3><p>Spring支持两种类型的事务管理：</p>
<p>编程式事务管理：这意味你通过编程的方式管理事务，给你带来极大的灵活性，但是难维护。</p>
<p>声明式事务管理：这意味着你可以将业务代码和事务管理分离，你只需用注解和XML配置来管理事务。</p>
<h3 id="【Spring】Spring框架的事务管理有哪些优点？"><a href="#【Spring】Spring框架的事务管理有哪些优点？" class="headerlink" title="【Spring】Spring框架的事务管理有哪些优点？"></a>【Spring】<strong>Spring框架的事务管理有哪些优点？</strong></h3><p>它为不同的事务API  如 JTA，JDBC，Hibernate，JPA 和JDO，提供一个不变的编程模式。</p>
<p>它为编程式事务管理提供了一套简单的API而不是一些复杂的事务API如</p>
<p>它支持声明式事务管理。</p>
<p>它和Spring各种数据访问抽象层很好得集成。</p>
<h3 id="【Spring】你更倾向用那种事务管理类型？"><a href="#【Spring】你更倾向用那种事务管理类型？" class="headerlink" title="【Spring】你更倾向用那种事务管理类型？"></a>【Spring】<strong>你更倾向用那种事务管理类型？</strong></h3><p>大多数Spring框架的用户选择声明式事务管理，因为它对应用代码的影响最小，因此更符合一个无侵入的轻量级容器的思想。声明式事务管理要优于编程式事务管理，虽然比编程式事务管理（这种方式允许你通过代码控制事务）少了一点灵活性。</p>
<h3 id="【Spring】-解释AOP"><a href="#【Spring】-解释AOP" class="headerlink" title="【Spring】 解释AOP"></a>【Spring】 解释AOP</h3><p>面向切面的编程，或AOP， 是一种编程技术，允许程序模块化横向切割关注点，或横切典型的责任划分，如日志和事务管理。</p>
<h3 id="【Spring】Aspect-切面"><a href="#【Spring】Aspect-切面" class="headerlink" title="【Spring】Aspect 切面"></a>【Spring】<strong>Aspect 切面</strong></h3><p>AOP核心就是切面，它将多个类的通用行为封装成可重用的模块，该模块含有一组API提供横切功能。比如，一个日志模块可以被称作日志的AOP切面。根据需求的不同，一个应用程序可以有若干切面。在Spring AOP中，切面通过带有@Aspect注解的类实现。</p>
<h3 id="【Spring】在Spring-AOP-中，关注点和横切关注的区别是什么？"><a href="#【Spring】在Spring-AOP-中，关注点和横切关注的区别是什么？" class="headerlink" title="【Spring】在Spring AOP 中，关注点和横切关注的区别是什么？"></a>【Spring】<strong>在Spring AOP 中，关注点和横切关注的区别是什么？</strong></h3><p>关注点是应用中一个模块的行为，一个关注点可能会被定义成一个我们想实现的一个功能。</p>
<p>横切关注点是一个关注点，此关注点是整个应用都会使用的功能，并影响整个应用，比如日志，安全和数据传输，几乎应用的每个模块都需要的功能。因此这些都属于横切关注点。</p>
<h3 id="【Spring】连接点"><a href="#【Spring】连接点" class="headerlink" title="【Spring】连接点"></a>【Spring】<strong>连接点</strong></h3><p>连接点代表一个应用程序的某个位置，在这个位置我们可以插入一个AOP切面，它实际上是个应用程序执行Spring AOP的位置。</p>
<h3 id="【Spring】通知"><a href="#【Spring】通知" class="headerlink" title="【Spring】通知"></a>【Spring】<strong>通知</strong></h3><p>通知是个在方法执行前或执行后要做的动作，实际上是程序执行时要通过SpringAOP框架触发的代码段。</p>
<p>Spring切面可以应用五种类型的通知：</p>
<p>before：前置通知，在一个方法执行前被调用</p>
<p>after：在方法执行之后调用的通知，无论方法执行是否成功</p>
<p>after-returning：仅当方法成功完成后执行的通知</p>
<p>after-throwing：在方法抛出异常退出时执行的通知</p>
<p>around：在方法执行之前和之后调用的通知</p>
<h3 id="【Spring】切点"><a href="#【Spring】切点" class="headerlink" title="【Spring】切点"></a>【Spring】<strong>切点</strong></h3><p>切入点是一个或一组连接点，通知将在这些位置执行。可以通过表达式或匹配的方式指明切入点。</p>
<h3 id="【Spring】什么是引入？"><a href="#【Spring】什么是引入？" class="headerlink" title="【Spring】什么是引入？"></a>【Spring】<strong>什么是引入？</strong></h3><p>引入允许我们在已存在的类中增加新的方法和属性。</p>
<h3 id="【Spring】什么是目标对象？"><a href="#【Spring】什么是目标对象？" class="headerlink" title="【Spring】什么是目标对象？"></a>【Spring】<strong>什么是目标对象？</strong></h3><p>被一个或者多个切面所通知的对象。它通常是一个代理对象。也指被通知（advised）对象。</p>
<h3 id="【Spring】什么是代理？"><a href="#【Spring】什么是代理？" class="headerlink" title="【Spring】什么是代理？"></a>【Spring】<strong>什么是代理？</strong></h3><p>代理是通知目标对象后创建的对象。从客户端的角度看，代理对象和目标对象是一样的。</p>
<h3 id="【Spring】有几种不同类型的自动代理？"><a href="#【Spring】有几种不同类型的自动代理？" class="headerlink" title="【Spring】有几种不同类型的自动代理？"></a>【Spring】<strong>有几种不同类型的自动代理？</strong></h3><p>BeanNameAutoProxyCreator</p>
<p>DefaultAdvisorAutoProxyCreator</p>
<p>Metadata autoproxying</p>
<h3 id="【Spring】什么是织入。什么是织入应用的不同点？"><a href="#【Spring】什么是织入。什么是织入应用的不同点？" class="headerlink" title="【Spring】什么是织入。什么是织入应用的不同点？"></a>【Spring】<strong>什么是织入。什么是织入应用的不同点？</strong></h3><p>织入是将切面和到其他应用类型或对象连接或创建一个被通知对象的过程。</p>
<p>织入可以在编译时，加载时，或运行时完成。</p>
<h3 id="【Spring】解释基于XML-Schema方式的切面实现"><a href="#【Spring】解释基于XML-Schema方式的切面实现" class="headerlink" title="【Spring】解释基于XML Schema方式的切面实现"></a>【Spring】<strong>解释基于XML Schema方式的切面实现</strong></h3><p>在这种情况下，切面由常规类以及基于XML的配置实现。</p>
<h3 id="【Spring】解释基于注解的切面实现"><a href="#【Spring】解释基于注解的切面实现" class="headerlink" title="【Spring】解释基于注解的切面实现"></a>【Spring】<strong>解释基于注解的切面实现</strong></h3><p>在这种情况下(基于@AspectJ的实现)，涉及到的切面声明的风格与带有java5标注的普通java类一致。</p>
<h3 id="【Spring】什么是Spring的MVC框架？"><a href="#【Spring】什么是Spring的MVC框架？" class="headerlink" title="【Spring】什么是Spring的MVC框架？"></a>【Spring】<strong>什么是Spring的MVC框架？</strong></h3><p>Spring 配备构建Web 应用的全功能MVC框架。Spring可以很便捷地和其他MVC框架集成，如Struts，Spring 的MVC框架用控制反转把业务对象和控制逻辑清晰地隔离。它也允许以声明的方式把请求参数和业务对象绑定。</p>
<h3 id="【Spring】DispatcherServlet"><a href="#【Spring】DispatcherServlet" class="headerlink" title="【Spring】DispatcherServlet"></a>【Spring】<strong>DispatcherServlet</strong></h3><p>Spring的MVC框架是围绕DispatcherServlet来设计的，它用来处理所有的HTTP请求和响应。</p>
<h3 id="【Spring】WebApplicationContext"><a href="#【Spring】WebApplicationContext" class="headerlink" title="【Spring】WebApplicationContext"></a>【Spring】<strong>WebApplicationContext</strong></h3><p>WebApplicationContext 继承了ApplicationContext  并增加了一些WEB应用必备的特有功能，它不同于一般的ApplicationContext ，因为它能处理主题，并找到被关联的servlet。</p>
<h3 id="【Spring】什么是Spring-MVC框架的控制器？"><a href="#【Spring】什么是Spring-MVC框架的控制器？" class="headerlink" title="【Spring】什么是Spring MVC框架的控制器？"></a>【Spring】<strong>什么是Spring MVC框架的控制器？</strong></h3><p>控制器提供一个访问应用程序的行为，此行为通常通过服务接口实现。控制器解析用户输入并将其转换为一个由视图呈现给用户的模型。Spring用一个非常抽象的方式实现了一个控制层，允许用户创建多种用途的控制器。</p>
<h3 id="【Spring】-Controller-注解"><a href="#【Spring】-Controller-注解" class="headerlink" title="【Spring】@Controller 注解"></a>【Spring】<strong>@Controller 注解</strong></h3><p>该注解表明该类扮演控制器的角色，Spring不需要你继承任何其他控制器基类或引用Servlet API。</p>
<h3 id="【Spring】-RequestMapping-注解"><a href="#【Spring】-RequestMapping-注解" class="headerlink" title="【Spring】@RequestMapping 注解"></a>【Spring】<strong>@RequestMapping 注解</strong></h3><p>该注解是用来映射一个URL到一个类或一个特定的方处理法上。</p>


    
    
    
	  <div class="full-width auto-padding tags">
      
        <a href="/tags/Java/">Java</a>
      
	  </div>
    
  </section>
</article>
    </div>
  
</section>


  <nav id="page-nav">
    
    
    <a class="next" rel="next" href="/archives/2018/page/2/">
      <span class="text">Next</span>
      <span class="icon icon-chevron-right"></span>
    </a>
    
  </nav>
  


      </div>
      <aside class='l_side'>
        
  <section class='m_widget links'>
<div class='header'>Links</div>
<div class='content'>
    <ul class="entry">
    
        <li><a class="flat-box" target="_blank" href="https://iiong.com/">
            <div class='name'>淮城一只猫</div>
        </a></li>
    
    </ul>
</div>
</section>

  <section class='m_widget categories'>
<div class='header'>Categories</div>
<div class='content'>
    
    <ul class="entry">
    
        <li><a class="flat-box" href="/categories/Android基础/"><div class='name'>Android基础</div><div class='badget'>1</div></a></li>
    
    </ul>
    
</div>
</section>

  
<div class="m_widget tagcloud">
    <div class="header">Tags</div>
    <div class='content'>
        <a href="/tags/Android/" style="font-size: 14px; color: #808080">Android</a> <a href="/tags/HTML/" style="font-size: 14px; color: #808080">HTML</a> <a href="/tags/Java/" style="font-size: 20px; color: #000">Java</a> <a href="/tags/Python/" style="font-size: 14px; color: #808080">Python</a>
    </div>
</div>



      </aside>
      <script>setLoadingBarProgress(60);</script>
    </div>
  </div>
  <footer id="footer" class="clearfix">

	<div class="social-wrapper">
  	
      
        <a href="https://github.com/stkevintan" class="social github"
          target="_blank" rel="external">
          <span class="icon icon-github"></span>
        </a>
      
        <a href="https://twitter.com/kevinsfork" class="social twitter"
          target="_blank" rel="external">
          <span class="icon icon-twitter"></span>
        </a>
      
        <a href="/atom.xml" class="social rss"
          target="_blank" rel="external">
          <span class="icon icon-rss"></span>
        </a>
      
    
  </div>
  
  <div>Theme <a href='https://github.com/stkevintan/hexo-theme-material-flow' class="codename">MaterialFlow</a> designed by <a href="http://keyin.me/" target="_blank">Kevin Tan</a>.</div>
  
</footer>


  <script>setLoadingBarProgress(80);</script>
  

<script src="//apps.bdimg.com/libs/jquery/2.1.4/jquery.min.js"></script>
<script src='//cdn.bootcss.com/node-waves/0.7.5/waves.min.js'></script>
<script src="//cdn.bootcss.com/scrollReveal.js/3.3.2/scrollreveal.min.js"></script>
<script src="/js/jquery.fitvids.js"></script>
<script>
	var GOOGLE_CUSTOM_SEARCH_API_KEY = "";
	var GOOGLE_CUSTOM_SEARCH_ENGINE_ID = "";
	var ALGOLIA_API_KEY = "";
	var ALGOLIA_APP_ID = "";
	var ALGOLIA_INDEX_NAME = "";
  var AZURE_SERVICE_NAME = "";
  var AZURE_INDEX_NAME = "";
  var AZURE_QUERY_KEY = "";
  var BAIDU_API_ID = "";
  var SEARCH_SERVICE = "hexo";
  var ROOT = "/"||"/";
  if(!ROOT.endsWith('/'))ROOT += '/';
</script>
<script src="/js/search.js"></script>
<script src="/js/app.js"></script>


  <script>setLoadingBarProgress(100);</script>
</body>
</html>
